隨筆-88  評論-77  文章-48  trackbacks-0

          作者:侯志江

          編寫自己的一個ping程序,可以說是許多人邁出網絡編程的第一步吧!!這個ping程序的源代碼經過我的修改和調試,基本上可以取代windows中自帶的ping程序. 各個模塊后都有我的詳細注釋和修改日志,希望能夠對大家的學習有所幫助!!

          /*? 本程序的主要源代碼來自MSDN網站, 筆者只是做了一些改進和注釋! 另外需要注意的是在Build之前,必須加入ws2_32.lib庫文件,否則會提示"error LNK2001:"的錯誤!*/

          /******************************************************************************\
          | Version 1.1 修改記錄:????????????????????????????????????????????????????????????????????????????????????????????????????????????? |
          |??? <1> 解決了socket阻塞的問題,從而能夠正確地處理超時的請求!??????????????????????????????????????????????????????? |
          |----------------------------------------------------------------------------------------------------|
          | Version 1.2 修改記錄:????????????????????????????????????????????????????????????????????????????????????????????????????????????? |
          |??? <1> 增加了由用戶控制發送ICMP包的數目的功能(即命令的第二個參數).????????????????????????????????????????????? |???
          |??? <2> 增加了對ping結果的統計功能.?????????????????????????????????????????????????????????????????????????????????????????? |
          \******************************************************************************/

          #pragma pack(4)

          #include
          #include
          #include

          #define ICMP_ECHO 8
          #define ICMP_ECHOREPLY 0

          #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)

          /* The IP header */
          typedef struct iphdr {
          unsigned int h_len:4; // length of the header
          unsigned int version:4; // Version of IP
          unsigned char tos; // Type of service
          unsigned short total_len; // total length of the packet
          unsigned short ident; // unique identifier
          unsigned short frag_and_flags; // flags
          unsigned char ttl;
          unsigned char proto; // protocol (TCP, UDP etc)
          unsigned short checksum; // IP checksum

          unsigned int sourceIP;
          unsigned int destIP;

          }IpHeader;

          //
          // ICMP header
          //
          typedef struct icmphdr {
          BYTE i_type;
          BYTE i_code; /* type sub code */
          USHORT i_cksum;
          USHORT i_id;
          USHORT i_seq;
          /* This is not the std header, but we reserve space for time */
          ULONG timestamp;
          }IcmpHeader;

          #define STATUS_FAILED 0xFFFF
          #define DEF_PACKET_SIZE??? 32
          #define DEF_PACKET_NUMBER? 4??? /* 發送數據報的個數 */
          #define MAX_PACKET 1024

          #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
          #define xfree(p) HeapFree (GetProcessHeap(),0,(p))

          void fill_icmp_data(char *, int);
          USHORT checksum(USHORT *, int);
          int decode_resp(char *,int ,struct sockaddr_in *);

          void Usage(char *progname){

          fprintf(stderr,"Usage:\n");
          fprintf(stderr,"%s [number of packets] [data_size]\n",progname);
          fprintf(stderr,"datasize can be up to 1Kb\n");
          ExitProcess(STATUS_FAILED);

          }
          int main(int argc, char **argv){

          WSADATA wsaData;
          SOCKET sockRaw;
          struct sockaddr_in dest,from;
          struct hostent * hp;
          int bread,datasize,times;
          int fromlen = sizeof(from);
          int timeout = 1000;
          int statistic = 0;? /* 用于統計結果 */?
          char *dest_ip;
          char *icmp_data;
          char *recvbuf;
          unsigned int addr=0;
          USHORT seq_no = 0;

          if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
          fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
          ExitProcess(STATUS_FAILED);
          }

          if (argc <2 ) {
          Usage(argv[0]);
          }
          sockRaw = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,WSA_FLAG_OVERLAPPED);

          //
          //注:為了使用發送接收超時設置(即設置SO_RCVTIMEO, SO_SNDTIMEO),
          //??? 必須將標志位設為WSA_FLAG_OVERLAPPED !
          //

          if (sockRaw == INVALID_SOCKET) {
          fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
          ExitProcess(STATUS_FAILED);
          }
          bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
          sizeof(timeout));
          if(bread == SOCKET_ERROR) {
          fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
          ExitProcess(STATUS_FAILED);
          }
          timeout = 1000;
          bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
          sizeof(timeout));
          if(bread == SOCKET_ERROR) {
          fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
          ExitProcess(STATUS_FAILED);
          }
          memset(&dest,0,sizeof(dest));

          hp = gethostbyname(argv[1]);

          if (!hp){
          addr = inet_addr(argv[1]);
          }
          if ((!hp) && (addr == INADDR_NONE) ) {
          fprintf(stderr,"Unable to resolve %s\n",argv[1]);
          ExitProcess(STATUS_FAILED);
          }

          if (hp != NULL)
          memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
          else
          dest.sin_addr.s_addr = addr;

          if (hp)
          dest.sin_family = hp->h_addrtype;
          else
          dest.sin_family = AF_INET;

          dest_ip = inet_ntoa(dest.sin_addr);

          //
          //? atoi函數原型是: int atoi( const char *string );
          //? The return value is 0 if the input cannot be converted to an integer !
          //
          if(argc>2)
          {
          ?times=atoi(argv[2]);
          ?if(times == 0)
          ? times=DEF_PACKET_NUMBER;
          }
          else
          ??? times=DEF_PACKET_NUMBER;

          if (argc >3)
          {
          ?datasize = atoi(argv[3]);
          ??? if (datasize == 0)
          ??????? datasize = DEF_PACKET_SIZE;
          ?if (datasize >1024)?? /* 用戶給出的數據包大小太大 */
          ?{
          ? fprintf(stderr,"WARNING : data_size is too large !\n");
          ? datasize = DEF_PACKET_SIZE;
          ?}
          }
          else
          ??? datasize = DEF_PACKET_SIZE;

          datasize += sizeof(IcmpHeader);

          icmp_data = (char*)xmalloc(MAX_PACKET);
          recvbuf = (char*)xmalloc(MAX_PACKET);

          if (!icmp_data) {
          fprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
          ExitProcess(STATUS_FAILED);
          }


          memset(icmp_data,0,MAX_PACKET);
          fill_icmp_data(icmp_data,datasize);

          //
          //顯示提示信息
          //
          fprintf(stdout,"\nPinging %s ....\n\n",dest_ip);


          for(int i=0;i{
          int bwrote;

          ((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);

          bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));
          if (bwrote == SOCKET_ERROR){
          if (WSAGetLastError() == WSAETIMEDOUT) {
          printf("Request timed out.\n");
          continue;
          }
          fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
          ExitProcess(STATUS_FAILED);
          }
          if (bwrote < datasize ) {
          fprintf(stdout,"Wrote %d bytes\n",bwrote);
          }
          bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);
          if (bread == SOCKET_ERROR){
          if (WSAGetLastError() == WSAETIMEDOUT) {
          printf("Request timed out.\n");
          continue;
          }
          fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
          ExitProcess(STATUS_FAILED);
          }
          if(!decode_resp(recvbuf,bread,&from))
          ?statistic++; /* 成功接收的數目++ */
          Sleep(1000);

          }
          ?
          /*
          Display the statistic result
          */
          fprintf(stdout,"\nPing statistics for %s \n",dest_ip);
          fprintf(stdout,"??? Packets: Sent = %d,Received = %d, Lost = %d (%2.0f%% loss)\n",times,
          ???? statistic,(times-statistic),(float)(times-statistic)/times*100);


          WSACleanup();
          return 0;

          }
          /*
          The response is an IP packet. We must decode the IP header to locate
          the ICMP data
          */
          int decode_resp(char *buf, int bytes,struct sockaddr_in *from) {

          IpHeader *iphdr;
          IcmpHeader *icmphdr;
          unsigned short iphdrlen;

          iphdr = (IpHeader *)buf;

          iphdrlen = (iphdr->h_len) * 4 ; // number of 32-bit words *4 = bytes

          if (bytes < iphdrlen + ICMP_MIN) {
          printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
          }

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

          if (icmphdr->i_type != ICMP_ECHOREPLY) {
          fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
          return 1;
          }
          if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
          fprintf(stderr,"someone else's packet!\n");
          return 1;
          }
          printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
          printf(" icmp_seq = %d. ",icmphdr->i_seq);
          printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
          printf("\n");
          return 0;

          }


          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) + (cksum & 0xffff);
          cksum += (cksum >>16);
          return (USHORT)(~cksum);
          }
          /*
          Helper function to fill in various stuff in our ICMP request.
          */
          void fill_icmp_data(char * icmp_data, int datasize){

          IcmpHeader *icmp_hdr;
          char *datapart;

          icmp_hdr = (IcmpHeader*)icmp_data;

          icmp_hdr->i_type = ICMP_ECHO;
          icmp_hdr->i_code = 0;
          icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
          icmp_hdr->i_cksum = 0;
          icmp_hdr->i_seq = 0;

          datapart = icmp_data + sizeof(IcmpHeader);
          //
          // Place some junk in the buffer.
          //
          memset(datapart,'E', datasize - sizeof(IcmpHeader));

          }

          /******************* 附: ping命令執行時顯示的畫面 ***************\
          *? C:\Documents and Settings\houzhijiang>ping 236.56.54.12?????????????? *
          *????????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Pinging 236.56.54.12 with 32 bytes of data:????????????????????????????????????? *
          *????????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Request timed out.???????????????????????????????????????????????????????????????????????? *
          *? Request timed out.???????????????????????????????????????????????????????????????????????? *
          *? Request timed out.???????????????????????????????????????????????????????????????????????? *
          *? Request timed out.???????????????????????????????????????????????????????????????????????? *
          *????????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Ping statistics for 236.56.54.12:????????????????????????????????????????????????????? *
          *???? Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),????????????????? *
          *????????????????????????????????????????????????????????????????????????????????????????????????????? *
          \*********************************************************/

          /*********************************************************\
          *? C:\Documents and Settings\houzhijiang>ping 127.0.0.1??????????????????? *
          *???????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Pinging 127.0.0.1 with 32 bytes of data:????????????????????????????????????????? *
          *???????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Reply from 127.0.0.1: bytes=32 time<1ms TTL=128??????????????????????? *
          *? Reply from 127.0.0.1: bytes=32 time<1ms TTL=128??????????????????????? *
          *? Reply from 127.0.0.1: bytes=32 time<1ms TTL=128??????????????????????? *
          *? Reply from 127.0.0.1: bytes=32 time<1ms TTL=128??????????????????????? *
          *???????????????????????????????????????????????????????????????????????????????????????????????????? *
          *? Ping statistics for 127.0.0.1:????????????????????????????????????????????????????????? *
          *???? Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),??????????????????? *
          *? Approximate round trip times in milli-seconds:???????????????????????????????? *
          *???? Minimum = 0ms, Maximum = 0ms, Average = 0ms??????????????????????? *
          *??????????????????????????????????????????????????????????????????????????????????????????????????? *
          \********************************************************/

          posted on 2006-04-27 09:44 崛起的程序員 閱讀(597) 評論(0)  編輯  收藏 所屬分類: c/c++
          主站蜘蛛池模板: 伊通| 轮台县| 汝南县| 棋牌| 楚雄市| 平山县| 开化县| 洪洞县| 义马市| 松桃| 托克托县| 望奎县| 穆棱市| 正阳县| 岳阳市| 道孚县| 大关县| 天等县| 凤山县| 清新县| 谷城县| 淮阳县| 宿州市| 东阳市| 元氏县| 屏山县| 资源县| 南涧| 兴安县| 承德县| 达孜县| 商城县| 贵南县| 汉川市| 汉源县| 易门县| 同仁县| 昭通市| 双柏县| 德昌县| 彭阳县|