TCP IP课程设计.docx

上传人:b****6 文档编号:3319873 上传时间:2022-11-21 格式:DOCX 页数:18 大小:130.18KB
下载 相关 举报
TCP IP课程设计.docx_第1页
第1页 / 共18页
TCP IP课程设计.docx_第2页
第2页 / 共18页
TCP IP课程设计.docx_第3页
第3页 / 共18页
TCP IP课程设计.docx_第4页
第4页 / 共18页
TCP IP课程设计.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

TCP IP课程设计.docx

《TCP IP课程设计.docx》由会员分享,可在线阅读,更多相关《TCP IP课程设计.docx(18页珍藏版)》请在冰豆网上搜索。

TCP IP课程设计.docx

TCPIP课程设计

枣庄学院

信息科学与工程学院

课程设计任务书

 

题目:

PING程序的设计与实现

 

学号:

姓名:

专业:

计算机科学与技术

课程:

TCP/IP协议实现与网络安全

指导教师:

王霞职称:

讲师

完成时间:

2012年6月----2012年6月

枣庄学院信息科学与工程学院制

年月日

课程设计任务书及成绩评定

课程设计的任务和具体要求

(1)熟悉原始套接字编程。

(2)了解网络的结构。

(3)了解网络传输底层协议。

 

指导教师签字:

日期:

指导教师评语

 

成绩:

指导教师签字:

日期:

课程设计所需软件、硬件等

 

课程设计进度计划

起至日期

工作内容

备注

参考文献、资料索引

序号

文献、资料名称

编著者

出版单位

【1】WinsockProgrammer'sFAQExamples:

Ping:

RawSocketsMethod,

【2】透析ICMP协议:

 协议原理,

【3】ping原理与ICMP协议,

目录

一.需求分析1

二.概要设计1

三.详细设计3

1.初始化模块3

2.功能控制模块3

3.数据报解读模块6

4.Ping测试模块8

四.测试结果11

五.实验总结12

 

一.需求分析

Ping的原理就是首先建立通道,然后发送包,对方接受后返回信息,这个包至少包括以下内容:

发送的时候,包的内容包括对方的ip地址和自己的地址,还有序列数;回送的时候包括双方地址,还有时间等,主要是接受方在都是在操作系统内核里做好的,时刻在监听。

Ping程序生成一个icmp“回送请求”,将其发送给目的主机。

通过检测是否可以收到目标主机的应答,便可以知道网络的连通性。

主要功能有:

实现ping功能。

程序能实现基本的ping操作,发送ICMP回显请求报文,接收显应答报文。

能记录路由。

程序提供了“-r”选项,用以记录从源主机到目的主机的路由。

(3)能输出指定条数的记录。

程序提供了“-n”选项,用以输出指定条数的记录。

(4)能按照指定大小输出每条记录。

程序提供了“datasize”选项,用以指定输出的数据报的大小。

(5)能输出用户帮助。

程序提供了用户帮助,显示程序提供的选项以及选项格式等。

二.概要设计

1)IntPing()

函数原型:

voidIntPing()

IntPing()函数用于初始化ping所需的全局变量,为各个变量赋初始值。

2)userHelp()

函数原型:

voiduserHelp()

userHelp()函数用于显示用户帮助信息。

当程序检查到参数错误或者没有必要的参数(如主机IP地址或者主机名)时,则会调用此函数显示帮助信息。

3)GetArgments()

函数原型:

voidGetArgments(intargc,char**argv)

GetArgments()函数用于获取用户提交的参数。

其中argc表示获取的参数个数,argv用于存储获取的参数,这两个形参和主函数中的形参表示的意义一样的。

4)checkSum()

函数原型:

USHORTcheckSum(USHORT*buffer,intsize)

checkSum()函数用于计算校验和。

计算过程是首先把数据报头中的校验和字段设置为0,然后对首部中每个16bit进行二字段进制反码求和(整个首部看成是由一串16bit的字组成),结果存在校验和字段中。

其中buffer用于存放ICMP数据,size表示ICMP报文大小。

5)FillCMPData()

函数原型:

voidFillCMPData()

FillCMPData()函数用于填充ICMP数据报中各个字段。

其中icmp_data表示ICMP数据,datasize表示ICMP报文大小。

6)reeRes()

函数原型:

voidreeRes()

reeRes()函数用于释放占用的资源,包括关闭初始化socket调用的函数的、关闭创建的socket和释放分配的内存等。

7)DecodeIPOptions()

函数原型:

voidDecodeIPOptions()

DecodeIPOptions()函数用于解读IP选项,从中读出从源主机到目的主机经过的路由,并输出路由信息。

Buf表示存放接收到的ICMP报文的缓冲区,bytes表示接收到的字节数。

8)DecodelICMPHeader()

函数原型:

voidDecodelICMPHeader(char*buf,intbytes,SOCKADDR_IN*from)

DecodelICMPHeader()函数用于解读ICMP报文信息。

Buf表示存放接收到的ICMP报文的缓冲区,bytes表示接收到的字节数,from表示发送ICMP回显应答的主机IP地址。

9)PingTest()

函数原型:

voidPingTest(inttimeout)

PingTest()函数用于进行Ping操作。

其中timeout表示设定的发送超时值。

三.详细设计

1.初始化模块

/*初始化变量函数*/

voidInitPing()

{

WSADATAwsaData;

icmp_data=NULL;

seq_no=0;

recvbuf=NULL;

RecordFlag=FALSE;

lpdest=NULL;

datasize=DEF_PACKET_SIZE;

PacketNum=5;

SucessFlag=FALSE;

/*Winsock初始化*/

if(WSAStartup(MAKEWORD(2,2),&wsaData)!

=0)

{

/*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/

printf("WSAStartup()failed:

%d\n",GetLastError());

return;

}

m_socket=INVALID_SOCKET;

}

2.功能控制模块

/*显示信息函数*/

voidUserHelp()

{

printf("UserHelp:

ping-r[datasize]\n");

printf("-rrecordroute\n");

printf("-nrecordamount\n");

printf("hostremotemachinetoping\n");

printf("datasizecanbeupto1KB\n");

ExitProcess(-1);

}

/*获取ping选项函数*/

voidGetArgments(intargc,char**argv)

{

inti;

intj;

intexp;

intlen;

intm;

/*如果没有指定目的地地址和任何选项*/

if(argc==1)

{

printf("\nPleasespecifythedestinationIPaddressandthepingoptionasfollow!

\n");

UserHelp();

}

for(i=1;i

{

len=strlen(argv[i]);

if(argv[i][0]=='-')

{

/*选项指示要获取记录的条数*/

if(isdigit(argv[i][1]))

{

PacketNum=0;

for(j=len-1,exp=0;j>=1;j--,exp++)

/*根据argv[i][j]中的ASCII值计算要获取的记录条数(十进制数)*/

PacketNum+=((double)(argv[i][j]-48))*pow(10,exp);

}

else

{

switch(tolower(argv[i][1]))

{

/*选项指示要获取路由信息*/

case'r':

RecordFlag=TRUE;

break;

/*没有按要求提供选项*/

default:

UserHelp();

break;

}

}

}

/*参数是数据报大小或者IP地址*/

elseif(isdigit(argv[i][0]))

{

for(m=1;m

{

if(!

(isdigit(argv[i][m])))

{

/*是IP地址*/

lpdest=argv[i];

break;

}

/*是数据报大小*/

elseif(m==len-1)

datasize=atoi(argv[i]);

}

}

/*参数是主机名*/

else

lpdest=argv[i];

}

}

/*求校验和函数*/

USHORTCheckSum(USHORT*buffer,intsize)

{

unsignedlongcksum=0;

while(size>1)

{

cksum+=*buffer++;

size-=sizeof(USHORT);

}

if(size)

{

cksum+=*(UCHAR*)buffer;

}

/*对每个16bit进行二进制反码求和*/

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(USHORT)(~cksum);

}

/*填充ICMP数据报字段函数*/

voidFillICMPData(char*icmp_data,intdatasize)

{

IcmpHeader*icmp_hdr=NULL;

char*datapart=NULL;

icmp_hdr=(IcmpHeader*)icmp_data;

/*ICMP报文类型设置为回显请求*/

icmp_hdr->i_type=ICMP_ECHO;

icmp_hdr->i_code=0;

/*获取当前进程IP作为标识符*/

icmp_hdr->i_id=(USHORT)GetCurrentProcessId();

icmp_hdr->i_cksum=0;

icmp_hdr->i_seq=0;

datapart=icmp_data+sizeof(IcmpHeader);

/*以数字0填充剩余空间*/

memset(datapart,'0',datasize-sizeof(IcmpHeader));

}

/*释放资源函数*/

voidFreeRes()

{

/*关闭创建的套接字*/

if(m_socket!

=INVALID_SOCKET)

closesocket(m_socket);

/*释放分配的内存*/

HeapFree(GetProcessHeap(),0,recvbuf);

HeapFree(GetProcessHeap(),0,icmp_data);

/*注销WSAStartup()调用*/

WSACleanup();

return;

}

3.数据报解读模块

/*解读IP选项头函数*/

voidDecodeIPOptions(char*buf,intbytes)

{

IpOptionHeader*ipopt=NULL;

IN_ADDRinaddr;

inti;

HOSTENT*host=NULL;

/*获取路由信息的地址入口*/

ipopt=(IpOptionHeader*)(buf+20);

printf("RR:

");

for(i=0;i<(ipopt->ptr/4)-1;i++)

{

inaddr.S_un.S_addr=ipopt->addr[i];

if(i!

=0)

printf("");

/*根据IP地址获取主机名*/

host=gethostbyaddr((char*)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr),AF_INET);

/*如果获取到了主机名,则输出主机名*/

if(host)

printf("(%-15s)%s\n",inet_ntoa(inaddr),host->h_name);

/*否则输出IP地址*/

else

printf("(%-15s)\n",inet_ntoa(inaddr));

}

return;

}

/*解读ICMP报头函数*/

voidDecodeICMPHeader(char*buf,intbytes,SOCKADDR_IN*from)

{

IpHeader*iphdr=NULL;

IcmpHeader*icmphdr=NULL;

unsignedshortiphdrlen;

DWORDtick;

staticinticmpcount=0;

iphdr=(IpHeader*)buf;

/*计算IP报头的长度*/

iphdrlen=iphdr->h_len*4;

tick=GetTickCount();

/*如果IP报头的长度为最大长度(基本长度是20字节),则认为有IP选项,需要解读IP选项*/

if((iphdrlen==MAX_IP_HDR_SIZE)&&(!

icmpcount))

/*解读IP选项,即路由信息*/

DecodeIPOptions(buf,bytes);

/*如果读取的数据太小*/

if(bytes

{

printf("Toofewbytesfrom%s\n",

inet_ntoa(from->sin_addr));

}

icmphdr=(IcmpHeader*)(buf+iphdrlen);

/*如果收到的不是回显应答报文则报错*/

if(icmphdr->i_type!

=ICMP_ECHOREPLY)

{

printf("nonechotype%drecvd\n",icmphdr->i_type);

return;

}

/*核实收到的ID号和发送的是否一致*/

if(icmphdr->i_id!

=(USHORT)GetCurrentProcessId())

{

printf("someoneelse'spacket!

\n");

return;

}

SucessFlag=TRUE;

/*输出记录信息*/

printf("%dbytesfrom%s:

",bytes,inet_ntoa(from->sin_addr));

printf("icmp_seq=%d.",icmphdr->i_seq);

printf("time:

%dms",tick-icmphdr->timestamp);

printf("\n");

icmpcount++;

return;

}

4.Ping测试模块

/*ping函数*/

voidPingTest(inttimeout)

{

intret;

intreadNum;

intfromlen;

structhostent*hp=NULL;

/*创建原始套接字,该套接字用于ICMP协议*/

m_socket=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);

/*如果套接字创建不成功*/

if(m_socket==INVALID_SOCKET)

{

printf("WSASocket()failed:

%d\n",WSAGetLastError());

return;

}

/*若要求记录路由选项*/

if(RecordFlag)

{/*IP选项每个字段用0初始化*/

ZeroMemory(&IpOption,sizeof(IpOption));

/*为每个ICMP包设置路由选项*/

IpOption.code=IP_RECORD_ROUTE;

IpOption.ptr=4;

IpOption.len=39;

ret=setsockopt(m_socket,IPPROTO_IP,IP_OPTIONS,(char*)&IpOption,sizeof(IpOption));

if(ret==SOCKET_ERROR)

{printf("setsockopt(IP_OPTIONS)failed:

%d\n",WSAGetLastError());

}

}/*设置接收的超时值*/

readNum=setsockopt(m_socket,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));

if(readNum==SOCKET_ERROR)

{

printf("setsockopt(SO_RCVTIMEO)failed:

%d\n",WSAGetLastError());

return;

}/*设置发送的超时值*/

timeout=1000;

readNum=setsockopt(m_socket,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));

if(readNum==SOCKET_ERROR)

{printf("setsockopt(SO_SNDTIMEO)failed:

%d\n",WSAGetLastError());

return;}

/*用0初始化目的地地址*/

memset(&DestAddr,0,sizeof(DestAddr));

/*设置地址族,这里表示使用IP地址族*/

DestAddr.sin_family=AF_INET;

if((DestAddr.sin_addr.s_addr=inet_addr(lpdest))==INADDR_NONE)

{/*名字解析,根据主机名获取IP地址*/

if((hp=gethostbyname(lpdest))!

=NULL)

{/*将获取到的IP值赋给目的地地址中的相应字段*/

memcpy(&(DestAddr.sin_addr),hp->h_addr,hp->h_length);

/*将获取到的地址族值赋给目的地地址中的相应字段*/

DestAddr.sin_family=hp->h_addrtype;

printf("DestAddr.sin_addr=%s\n",inet_ntoa(DestAddr.sin_addr));

}/*获取不成功*/

else

{printf("gethostbyname()failed:

%d\n",WSAGetLastError());

return;

}

}/*数据报文大小需要包含ICMP报头*/

datasize+=sizeof(IcmpHeader);

/*根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存的内容将被初始化为0*/

icmp_data=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);

recvbuf=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);

/*如果分配内存不成功*/

if(!

icmp_data)

{printf("HeapAlloc()failed:

%d\n",GetLastError());

return;

}

/*创建ICMP报文*/

memset(icmp_data,0,MAX_PACKET);

FillICMPData(icmp_data,datasize);

while

(1)

{staticintnCount=0;

intwriteNum;

/*超过指定的记录条数则退出*/

if(nCount++==PacketNum)

break;

/*计算校验和前要把校验和字段设置为0*/

((IcmpHeader*)icmp_data)->i_cksum=0;

/*获取操作系统启动到现在所经过的毫秒数,设置时间戳*/

((IcmpHeader*)icmp_data)->timestamp=GetTickCount();

/*设置序列号*/

((IcmpHeader*)icmp_data)->i_seq=seq_no++;

/*计算校验和*/

((IcmpHeader*)icmp_data)->i_cksum=CheckSum((USHORT*)icmp_data,datasize);/*开始发送ICMP请求*/

writeNum=sendto(m_socket,icmp_data,datasize,0,(structsockaddr*)&DestAddr,sizeof(DestAddr));

/*如果发送不成功*/

if(writeNum==SOCKET_ERROR)

{/*如果是由于超时不成功*/

if(WSAGetLastError()==WSAETIMEDOUT)

{printf("timedout\n");

continue;

}/*其他发送不成功原因*/

printf("sendto()failed:

%d\n",WSAGetLastError());

return;

}/*

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1