1、Type echo消息的类型为8 echo reply 的消息类型为0.Code=0Checksum 为从TYPE开始到IP包结束的校验和,也就是校验整个ICMP报文Identifier 如果 code = 0, identifier用来匹配echo和echo reply消息Sequence Number功能描述:收到echo 消息必须回应 echo reply 消息. identifier 和 sequence number 可能被发送echo的主机用来匹配返回的echo reply消息.例如: identifier 可能用于类似于TCP或UDP的 port用来标示一个会话, 而sequen
2、ce number 会在每次发送echo请求后递增. 收到echo的主机或路由器返回同一个值与之匹配2 数据结构(1)IP报头格式/定义IP首部 typedef struct _iphdr unsigned char h_lenver; /4 位IP版本号+4位首部长度 unsigned char tos; /8位服务类型TOS unsigned short total_len; /16位IP包总长度(字节) unsigned short ident; /1 6位标识, 用于辅助IP包的拆装,本实验不用,置零unsigned short frag_and_flags; /3位标志位+13位偏移
3、位, 也是用于IP包的拆装,本实验不用,置零 unsigned char ttl; /8位IP包生存时间 TTL unsigned char proto; /8位协议 (TCP, UDP 或其他), 本实验置ICMP,置为1 unsigned short checksum; /16位IP首部校验和,最初置零,等所有包头都填写正确后,计算并替换. unsigned int sourceIP; /32位源IP地址 unsigned int destIP; /32位目的IP地址IP_HEADER;(2)ICMP报头格式/定义ICMP首部typedef struct _icmphdr unsigned
4、 char i_type; /8位类型, 本实验用 8: ECHO 0:ECHO REPLY unsigned char i_code; /8位代码, 本实验置零unsigned short i_cksum; /16位校验和, 从TYPE开始,直到最后一位用户数据,如果为字节数为奇数则补充一位unsigned short i_id ; /识别号(一般用进程号作为识别号), 用于匹配ECHO和ECHO REPLY包 unsigned short i_seq ; /报文序列号, 用于标记ECHO报文顺序 unsigned int timestamp; /时间戳ICMP_HEADER;3总体设计IC
5、MP协议中的发送、接收ICMP回送请求报文,回送应答报文流程图。4VC中网络套接字Winsock编程基础在VC中进行WINSOCK的API编程开发的时候,需要在项目中使用下面三个文件,否则会出现编译错误。1WINSOCK.H: 这是WINSOCK API的头文件,需要包含在项目中。2: WINSOCK API连接库文件。在使用中,一定要把它作为项目的非缺省的连接库包含到项目文件中去。3: WINSOCK的动态连接库,位于WINDOWS的安装目录下。几个基本的套接字:1、创建套接字socket() 功能:使用前创建一个新的套接字格式:SOCKET PASCAL FAR socket(int af
6、,int type,int procotol);参数:af: 通信发生的区域type: 要建立的套接字类型procotol: 使用的特定协议2、指定本地地址bind()将套接字地址与所创建的套接字号联系起来。int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR * name,int namelen);s: 是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。其它:没有错误,bind()返回0,否则SOCKET_ERROR地址结构说明:struct sockaddr_inshort sin_family;/AF_INETu
7、_short sin_port;/16位端口号,网络字节顺序struct in_addr sin_addr;/32位IP地址,网络字节顺序char sin_zero8;/保留3建立套接字连接connect()和accept()共同完成连接工作int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);同上4、监听连接listen()用于面向连
8、接服务器,表明它愿意接收连接。int PASCAL FAR listen(SOCKET s, int backlog);5、数据传输send()与recv()数据的发送与接收int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);buf:指向存有传输数据的缓冲区的指针。6、多路复用select()用来检测一个或多个套接字状态。int PASCAL FAR select(int
9、nfds,fd_set FAR * readfds,fd_set FAR * writefds, fd_set FAR * exceptfds,const struct timeval FAR * timeout);readfds:指向要做读检测的指针writefds:指向要做写检测的指针exceptfds:指向要检测是否出错的指针timeout:最大等待时间7、关闭套接字closesocket()关闭套接字sBOOL PASCAL FAR closesocket(SOCKET s);5 部分程序代码 /初始化SOCKET WSADATA wsaData; iErrorCode = WSASt
10、artup(MAKEWORD(2,2),&wsaData); CheckSockError(iErrorCode, WSAStartup); sockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_ICMP); /原始套接字 CheckSockError(sockRaw, socket /设置超时时间 timeout = time; iErrorCode = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout);/设置接受延时SO_RCVTIMEO iErrorCo
11、de = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&/设置发送延时SO_SNDTIMEO /获得目标主机IP memset(&dest,0,sizeof(dest);/初始化dest结构 _family = AF_INET; /填充SOCKADDR_IN结构内容 if(_addr.s_addr = inet_addr(lpdest) = INADDR_NONE) if(hp = gethostbyname(lpdest) != NULL) /目的主机名字不为空 memcpy(&(_addr),hp-h_addr_list0,hp-h_l
12、ength); _family = hp-h_addrtype; printf(_addr = %sn,inet_ntoa(_addr); else CheckSockError(SOCKET_ERROR, gethostbyname() /创建ICMP数据包 datasize += sizeof(ICMP_HEADER); /包长 icmp_data = (char *)malloc(1024); /创建icmp数据报内存空间 recvbuf = (char *)malloc(1024); /接收icmp包缓冲区 if(!icmp_data) | (!recvbuf) CheckSockEr
13、ror(SOCKET_ERROR, malloc() memset(icmp_data,0,MAX_PACKET); /初始化icmp_data FillICMPData(icmp_data,datasize); /填充icmp包 printf(Pinging %s with %d bytes of data(timeout = %d ms):nn,inet_ntoa(_addr),datasize,timeout ); /发送与接收ICMP数据包 while(1) memset(recvbuf,0,MAX_PACKET); /初始化接受缓冲区 static int nCount = 0; /
14、设置发送icmp包的次数,一般为4 if(nCount+ =4) break; (ICMP_HEADER*)icmp_data)-i_cksum = 0; /初设校验和为0timestamp = GetTickCount(); /获得目前时间i_seq = seq_no+; /icmp数据报的序列号i_cksum = checksum(USHORT*)icmp_data,datasize);/计算校验和 iErrorCode = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest);/发送icmp数据报
15、 if(iErrorCode = SOCKET_ERROR) /错误检查 if(WSAGetLastError() = WSAETIMEDOUT) printf(timed outn continue; sendto() if(iErrorCode i_type = ICMP_ECHO; /发送ping / Request an ICMP echoi_code = 0; /代码字段为0i_id = (USHORT)GetCurrentProcessId(); /获得当前进程号i_seq = 0; /初始化序列号 datapart = icmp_data + sizeof(ICMP_HEADER
16、); /加上icmp包头 / / Place some junk in the buffer memset(datapart,E, datasize - sizeof(ICMP_HEADER); /填充datapart/计算检验和USHORT checksum(USHORT *buffer, int size) unsigned long cksum=0; while (size 1) cksum += *buffer+; size -= sizeof(USHORT); if (size) cksum += *(UCHAR*)buffer; cksum = (cksum 16) + (cksu
17、m & 0xffff); cksum += (cksum 16); return (USHORT)(cksum);/ICMP解包程序void DecodeICMPHeader(char *buf, int bytes, struct sockaddr_in *from) IP_HEADER *iphdr = NULL; ICMP_HEADER *icmphdr = NULL; unsigned short iphdrlen; DWORD tick; iphdr = (IP_HEADER *)buf; / Number of 32-bit words * 4 = bytes iphdrlen=
18、sizeof(unsigned long) * (iphdr-h_lenver & 0xf); /计算ip包头长度 tick = GetTickCount(); if(bytes sin_addr); icmphdr = (ICMP_HEADER*)(buf + iphdrlen); if (icmphdr-i_type != ICMP_ECHOREPLY) /不是回送响应(ping应答),丢弃nonecho type %d recvdn, icmphdr-i_type); return; / Make sure this is an ICMP reply to something we se
19、nt!i_id != (USHORT)GetCurrentProcessId() /id号不符合,丢弃someone elses packet!n return ;%d bytes from %s:, bytes, inet_ntoa(from- /输出正在使用的ip地址 icmp_seq = %d. i_seq); /输出序列号 time: %d ms, tick - icmphdr-timestamp); /输出所用时间 return;6实验结果 该程序用来检验网络中的一台目标主机是否可达,其功能相当与Windows系统自带的ping命令。例如当程序检验地址为218.199.74.46的目标主机时,可以返回如下信息。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1