原始套接口的ping命令编程

来源:互联网 发布:河北网络干部学院官网 编辑:程序博客网 时间:2024/05/16 10:49

原始套接口(SOCK_RAW)允许对较低层协议(如IP或ICMP)进行直接访问,常用于检验新的网络协议实现,也可用于测试新配置或安装的网络设备。创建一个原始套接口时,一般格式如下: 

SOCKET sockid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//ICMP协议
SOCKET sockid=socket(AF_INET,SOCK_RAW,IPPROTO_IP);//IP协议

以下是利用ICMP协议实现的PING命令:

#include <WINSOCK2.H>  #pragma comment(lib,"ws2_32")  #include <stdio.h>    //--------------------①头部格式--------------  /************************************************************************/  /* IP头部                                                               */  /************************************************************************/  typedef struct IP_Header//20B的IP固定头部  {      UCHAR ipVer;        //1B 4b版本号+4b头长度      UCHAR ipTOS;        //1B 服务类型      USHORT ipLength;    //2B 总长度(IP数据报的长度)      USHORT ipID;        //2B 标识(唯一标识发送的每一个数据报)      USHORT ipFlags;        //2B 3b标志+13b分段偏移      UCHAR ipTTL;        //1B 生存时间TTL      UCHAR ipProtocol;    //1B 上层协议标识(TCP、UDP、ICMP)          USHORT ipChecksum;    //2B 头部效验和      ULONG ipSource;        //4B 源IP地址      ULONG ipDestination;//4B 目的IP地址  }IPHDR,*PIPHDR;  /************************************************************************/  /* ICMP头部                                                             */  /************************************************************************/  typedef struct ICMP_Header//8B的ICMP头部  {      UCHAR icmp_type;    //1B 类型      UCHAR icmp_code;    //1B 代码      USHORT icmp_checksum;//2B 效验和      USHORT icmp_id;        //2B 标识符(通常设置为进程ID)      USHORT icmp_seq;    //2B 序号(0~3)  }ICMPHDR,*PICMPHDR;  //------------------------②函数声明-----------------------  USHORT checksum(USHORT *buff,int size);  int SetTimeout(SOCKET s,long nTime);  //------------------------③main函数-----------------------  int main()  {      WSADATA wsaData;      if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)       {           printf("WSAStartup Failed,Error=【%d】\n",WSAGetLastError());           return 1;       }       else           printf("加载成功\n");       //----------创建原始套接字----------------      SOCKET sRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//创建原始套接字      //----------设置接收超时-----------------      struct timeval tv;      tv.tv_sec=1;      int F=SetTimeout(sRaw,tv.tv_sec);      if (F)      {          printf("setsockopt() Failed,Error=%d\n",WSAGetLastError());          return 1;      }      else          printf("设置接收超时为%d秒\n",tv.tv_sec);      //----------绑定-------------      struct sockaddr_in Sadd;      Sadd.sin_family=AF_INET;      Sadd.sin_port=htons(1111);      Sadd.sin_addr.s_addr=inet_addr("192.168.31.1");      if (bind(sRaw,(sockaddr*)&Sadd,sizeof(Sadd))==SOCKET_ERROR)      {          printf("bind() Failed,Error=%d\n",WSAGetLastError());          return 1;      }      else          printf("绑定成功,本地IP地址:【%s】,端口号:【%d】\n",inet_ntoa(Sadd.sin_addr),ntohs(Sadd.sin_port));      //---------目的IP地址(要ping的IP地址)--------------      struct sockaddr_in Dest;      Dest.sin_family=AF_INET;      Dest.sin_addr.s_addr=inet_addr("192.168.32.1");      //----------创建ICMP包----------------      char buff[sizeof(ICMPHDR)];        //char buff[sizeof(ICMPHDR)+32];      PICMPHDR pIcmp=(ICMPHDR*)buff;      // 1)填写ICMP包(公共部分)      pIcmp->icmp_type=8;      pIcmp->icmp_code=0;      pIcmp->icmp_id=(USHORT)GetCurrentProcessId();    //当前进程ID      //memset(&buff[sizeof(ICMPHDR)],'E',32);      //----------开始准备发送和接收ICMP封包--------------      char recvBuf[200];      struct sockaddr_in R_Dest;      int L_R_Dest=sizeof(struct sockaddr_in);      while (true)      {          static USHORT nSeq=0;    //seq由0开始          static int nCount=0;    //发送4个包          if (nCount++==4)              break;          //2)继续填写ICMP封包数据(可变部分)          pIcmp->icmp_checksum=0;          pIcmp->icmp_seq=nSeq++;          pIcmp->icmp_checksum=checksum((USHORT*)buff,sizeof(ICMPHDR));    //效验          //pIcmp->icmp_checksum=checksum((USHORT*)buff,sizeof(ICMPHDR)+32);          //-------------发送-------------          int time_send=GetTickCount();          int nRet=sendto(sRaw,buff,sizeof(ICMPHDR),0,(SOCKADDR*)&Dest,sizeof(Dest));          //int nRet=sendto(sRaw,buff,sizeof(ICMPHDR)+32,0,(SOCKADDR*)&Dest,sizeof(Dest));          if (nRet==SOCKET_ERROR)          {              printf("sendto() Failed,Error=%d\n",WSAGetLastError());              return 1;          }          //-------------接收---------------          int RRet=recvfrom(sRaw,recvBuf,sizeof(recvBuf),0,(sockaddr*)&R_Dest,&L_R_Dest);          int time_recv=GetTickCount();          if (nRet==SOCKET_ERROR)          {              if (WSAGetLastError()==WSAETIMEDOUT)              {                  printf("timed out\n");                  continue;              }              printf("recvfrom() Failed,Error=%d\n",WSAGetLastError());              return 1;          }          //------------解析----------------          PICMPHDR pRecvIcmp=(ICMPHDR*)(recvBuf+sizeof(IPHDR));          if (RRet<(nRet+sizeof(IPHDR)))              printf("从%s收到的数据过少\n",inet_ntoa(R_Dest.sin_addr));          if (pRecvIcmp->icmp_type!=0)    //不是应答          {              printf("这不是我要接收的应答报文,该报文类型为%d\n",pRecvIcmp->icmp_type);              return 1;          }          if (pRecvIcmp->icmp_id!=GetCurrentProcessId())          {              printf("这是别人的包\n");              return 1;          }          printf("%d bytes from %s,icmp_seq=%d,time:%d ms\n",RRet,inet_ntoa(R_Dest.sin_addr),pRecvIcmp->icmp_seq,time_recv-time_send);          Sleep(1000);      }      closesocket(sRaw);      WSACleanup();      return 0;  }  //---------------④效验函数-----------------  USHORT checksum(USHORT *buff,int size)  {      unsigned long cksum=0;      while (size>1)      {          cksum+=*buff++;          size-=2;      }      if (size==1)          cksum+=*(UCHAR*)buff;      cksum=(cksum>>16)+(cksum&0xffff);      cksum+=(cksum>>16);      USHORT ans=(USHORT)~cksum;      return (ans);  }  //---------------⑤接收超时函数---------------  int SetTimeout(SOCKET s,long nTime)  {      int ret=setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&nTime,sizeof(nTime));      return ret;  }  
运行程序效果如下:


原文链接:http://blog.csdn.net/akof1314/article/details/5663536

原创粉丝点击