c语言实现ping
来源:互联网 发布:手机淘宝信誉评级在哪 编辑:程序博客网 时间:2024/05/22 13:25
在dos输入ping+主机名可以知道主机是否可达,这是网际控制报文协议ICMP的一个应用,为了更有效的转发IP数据报和提高交付成功机会,封装在ip数据包中的ICMP允许主机或路由器报告差错情况和提供异常情况的报告。更具体点的,向目的主机发送ICMP回送请求报文,收到此报文的主机必须向源主机或路由器发送ICMP回送回答报文。ICMP的报文格式是,常见的ICMP报文类型如下图
要模拟ping的过程,就是先数据封装一个ICMP报文,发送并对接收的ip数据报文处理的过程。以下为代码
#include<stdio.h>#include<Winsock2.h>#include<ws2tcpip.h>#include<stdlib.h>#include<malloc.h>#include<string.h>#pragma comment("WS2_32.lib")#define DEF_ICMP_TIMEOUT 3000 //定义超时为3秒#define ICMP_ECHO_REQUEST 8 //定义回显请求类型#define DEF_ICMP_DATA_SIZE 20 //定义发送数据长度#define DEF_ICMP_PACK_SIZE 32 //定义数据包长度#define MAX_ICMP_PACKET_SIZE 1024 //定义最大数据包长度#define ICMP_ECHO_REPLY 0 //定义回显应答类型/* *IP报头结构 */typedef struct{ byte h_len_ver ; //IP版本号 byte tos ; // 服务类型 unsigned short total_len ; //IP包总长度 unsigned short ident ; // 标识 unsigned short frag_and_flags ; //标志位 byte ttl ; //生存时间 byte proto ; //协议 unsigned short cksum ; //IP首部校验和 unsigned long sourceIP ; //源IP地址 unsigned long destIP ; //目的IP地址} IP_HEADER ;/* *定义ICMP数据类型 */typedef struct{ byte type ; //类型-----8 byte code ; //代码-----8 unsigned short cksum ; //校验和------16 unsigned short id ; //标识符-------16 unsigned short seq ; //序列号------16 unsigned int choose ; //选项-------32} ICMP_HEADER ;typedef struct{ int usSeqNo ; //记录序列号 DWORD dwRoundTripTime ; //记录当前时间 byte ttl ; //生存时间 IN_ADDR dwIPaddr ; //源IP地址} DECODE_RESULT ;//将命令行参数转换为ip地址unsigned long GetIp(char *str){ unsigned long ulDestIP=inet_addr(str); if(ulDestIP==INADDR_NONE){ HOSTENT *pHostent=gethostbyname(str); if(pHostent){ ulDestIP=(*(IN_ADDR*)pHostent->h_addr).s_addr; } pHostent=gethostbyname("www.baidu.com"); if (pHostent == NULL) { perror("getaddrinfo"); ulDestIP=2; } } return ulDestIP;}//产生网际校验和unsigned short GenerateChecksum(unsigned short *pBuf,int iSize){ unsigned long cksum=0; while(iSize>1){ cksum+=*pBuf++;//将待校验的数据每16位逐位相加保存在cksum中 iSize-=sizeof(unsigned short);//每16位加完则将带校验数据量减16 } // if(iSize){ cksum+=*(unsigned char *)pBuf; } cksum=(cksum>>16)+(cksum&0xffff); cksum+=(cksum>>16); return (unsigned short)(~cksum);}//解析应答信息int DecodeIcmpResponse(char *pBuf,int iPacketSize,DECODE_RESULT *stDecodeResult){ //获取收到的IP数据包的首部信息 IP_HEADER *pIpHrd=(IP_HEADER *)pBuf; int iIpHrdLen=20; if(iPacketSize<(int)(iIpHrdLen+sizeof(ICMP_HEADER))){ return 0; } //指针指向ICMP报文的首地址 ICMP_HEADER *pIcmpHrd=(ICMP_HEADER *)(pBuf+iIpHrdLen); unsigned short usID,usSquNo; //获取的数据包的type字段为ICMP_ECHO_REPLY,即受到一个回显应答的报文 if(pIcmpHrd->type==ICMP_ECHO_REPLY){ usID=pIcmpHrd->id; //接受到的是网络字节顺序的seq字段信息,需要转成主机字节顺序 usSquNo=ntohs(pIcmpHrd->seq); } if(usID!=GetCurrentProcessId()||usSquNo!=stDecodeResult->usSeqNo){ return 0; } if(pIcmpHrd->type==ICMP_ECHO_REPLY){ stDecodeResult->ttl=pIpHrd->ttl; stDecodeResult->dwIPaddr.s_addr=pIpHrd->sourceIP; stDecodeResult->dwRoundTripTime=GetTickCount()-stDecodeResult->dwRoundTripTime; return 1; } return 0;}//填充目的的socketint CreateSocket(unsigned long ulDestIP){ //填充目的的socket SOCKADDR_IN destSockAddr; ZeroMemory(&destSockAddr,sizeof(SOCKADDR_IN)); destSockAddr.sin_family=AF_INET; destSockAddr.sin_addr.s_addr=ulDestIP; destSockAddr.sin_port = htons(0); //初始化WinSock WORD wVersionRequested = MAKEWORD(2,2); WSADATA wsaData; if(WSAStartup(wVersionRequested,&wsaData) != 0) { printf("初始化WinSock失败!\n") ; return ; }//使用ICMP协议创建Raw Socket SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED); if(sockRaw == INVALID_SOCKET) { printf("WSASocket() failed: %d\n", WSAGetLastError()); return ; } //设置端口属性 int iTimeout=DEF_ICMP_TIMEOUT; if(setsockopt(sockRaw,SOL_SOCKET, SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout))==SOCKET_ERROR){ printf("设置SO_RCVTIMEO失败\n"); } if(setsockopt(sockRaw,SOL_SOCKET, SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout))==SOCKET_ERROR){ printf("设置SO_SNDTIMEO失败\n"); } //定义发送的数据段 char IcmpSendBuf[DEF_ICMP_PACK_SIZE] ; //填充ICMP数据包各字段 ICMP_HEADER * pIcmpHeader=(ICMP_HEADER *)IcmpSendBuf; pIcmpHeader->type=ICMP_ECHO_REQUEST; pIcmpHeader->code=0; pIcmpHeader->id=(unsigned short)GetCurrentProcessId(); memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE); //循环发送4个请求回显icmp数据包 DECODE_RESULT stDecodeResult; int usSeqNo; for(usSeqNo=0;usSeqNo<=3;usSeqNo++){ pIcmpHeader->seq=htons(usSeqNo); pIcmpHeader->cksum=0; pIcmpHeader->cksum=GenerateChecksum((unsigned short *)IcmpSendBuf,sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE); //记录序列号和当前时间 stDecodeResult.usSeqNo=usSeqNo; stDecodeResult.dwRoundTripTime=GetTickCount(); //发送ICMP的EchoRequest数据包 if(sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(SOCKADDR*)&destSockAddr,sizeof(destSockAddr))==SOCKET_ERROR){ //如果主机不可达则直接退出 if(WSAGetLastError()==WSAEHOSTUNREACH){ return 0; } } SOCKADDR_IN from; int iFromLen=sizeof(from); int iReadLen; //定义接收的数据包 char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE] ; while(1){ iReadLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(SOCKADDR*)&from,&iFromLen); if(iReadLen!=SOCKET_ERROR){//正确接受到一个ICMP报文 if(DecodeIcmpResponse(IcmpRecvBuf , sizeof(IcmpRecvBuf) , &stDecodeResult)==1) { printf("来自 %s 的回复: 字节 = %d 时间 = %dms TTL = %d\n" , inet_ntoa(stDecodeResult.dwIPaddr) , iReadLen - 20,stDecodeResult.dwRoundTripTime ,stDecodeResult.ttl) ; } break ; }else if(WSAGetLastError()==WSAETIMEDOUT){//接受超时 printf("time out ! *****\n") ; break ; }else{ printf("发生未知错误!\n") ; break ; } } } printf("\nping complete.\n"); closesocket(sockRaw); WSACleanup(); return 0;}int main(int argc,char *argv[]){ char *arr=(char *)malloc(sizeof(char)); unsigned long ulDestIP;//ip地址 if(argv[1]!=NULL){ ulDestIP=GetIp(argv[1]); }else{ printf("请输入ip地址:"); scanf("%s",arr); ulDestIP=GetIp(arr); } CreateSocket(ulDestIP);}
0 0
- c语言实现ping
- c语言实现ping源码
- C语言实现PING程序
- 用C 语言实现 Ping
- C语言实现PING功能
- ping程序-c语言实现
- C 语言实现 ping 程序
- 用C语言实现Ping程序功能
- 用C语言实现Ping程序功能
- 用C语言实现ping程序
- 用C语言实现Ping程序功能
- 用C语言实现Ping程序功能
- C语言实现ICMP协议Ping命令
- 用C语言实现Ping程序功能
- linux下ping的C语言实现
- 基于C语言实现的Ping程序
- 基于C语言实现的Ping程序
- 用C语言实现Ping程序功能
- 【Git】git将本地代码提交到远程仓库
- 欢迎使用CSDN-markdown编辑器
- ajax的data传参的两种方式
- How to Secure an Android App 如何保护Android应用程序
- 平面设计之展示牌篇
- c语言实现ping
- 1006. Sign In and Sign Out (25)
- 用lua输出斐波那契fibonacci数列 : 0, 1,1, 2, 3, 5, 8, 13, 21, 34, 55, 89
- C语言及程序设计初步—第7讲
- 大型网站架构之分布式消息队列
- OkHttp:Java 平台上的新一代 HTTP 客户端
- Linux设备驱动第三天(字符设备驱动、cdev)
- 海狐联合创始人王哲: 做产品做市场,让用户体验更爽
- Android 属性动画 源码解析 深入了解其内部实现