user-0 提问: 菜鸟求助，ping程序无法记录时间

回复:
user: user-0
content: 引用 8 楼 zhao4zhong1 的回复:我看错了，可以不带"-t "前缀的。上帖第224行去掉注释。 听说Win7下不让SOCK_RAW了，或者需要提权啥的，搜“Win7 SOCK_RAW”。 我是Windows Server 2003 为什么我用你上面改过的代码，确跑不出你  Limitations on Raw Sockets  On Windows 7, Windows Vista, Windows XP with Service Pack 2 (SP2), and Windows XP with Service Pack 3 (SP3), the ability to send traffic over raw sockets has been restricted in several ways: TCP data cannot be sent over raw sockets. UDP datagrams with an invalid source address cannot be sent over raw sockets. The IP source address for any outgoing UDP datagram must exist on a network interface or the datagram is dropped. This change was made to limit the ability of malicious code to create distributed denial-of-service attacks and limits the ability to send spoofed packets (TCP/IP packets with a forged source IP address). A call to the bind function with a raw socket for the IPPROTO_TCP protocol is not allowed.  哎，正如你所说，win7限制SOCK_RAW的使用了，看来得找其他方案实现ping了。非常感谢你热心的帮助，谢谢！

user: user-1
content: 我看错了，可以不带"-t "前缀的。上帖第224行去掉注释。 听说Win7下不让SOCK_RAW了，或者需要提权啥的，搜“Win7 SOCK_RAW”。 我是Windows Server 2003

user: user-1
content: GetTickCount计时精度不如timeGetTime #include <stdio.h> #include <stdlib.h> #include <winsock.h> #include <mmsystem.h> #pragma comment(lib, "ws2_32") #pragma comment(lib, "winmm") #define ICMP_ECHOREPLY 0 //ICMP回应答复 #define ICMP_ECHOREQ 8 //ICMP回应请求 #define REQ_DATASIZE 32 //请求数据报大小 #include <iostream> using namespace std;  //定义IP首部格式 typedef struct _IPHeader {     u_char VIHL; //版本和首部长度     u_char ToS; //服务类型     u_short TotalLen; //总长度     u_short ID; //标识号     u_short Frag_Flags; //片偏移量     u_char TTL; //生存时间     u_char Protocol; //协议     u_short Checksum; //首部校验和     struct in_addr SrcIP; //源IP地址     struct in_addr DestIP; //目的地址 } IPHDR, *PIPHDR;  //定义ICMP首部格式 typedef struct _ICMPHeader {     u_char Type; //类型     u_char Code; //代码     u_short Checksum; //首部校验和     u_short ID; //标识     u_short Seq; //序列号     char Data; //数据 } ICMPHDR, *PICMPHDR;  //定义ICMP回应请求 typedef struct _ECHOREQUEST {     ICMPHDR icmpHdr;     DWORD dwTime;     char cData[REQ_DATASIZE]; } ECHOREQUEST, *PECHOREQUEST;  //定义ICMP回应答复 typedef struct _ECHOREPLY {     IPHDR ipHdr;     ECHOREQUEST echoRequest;     char cFiller[256]; } ECHOREPLY, *PECHOREPLY;  //计算校验和 u_short checksum(u_short *buffer, int len) {     register int nleft = len;     register u_short *w = buffer;     register u_short answer;     register int sum = 0;     //使用32位累加器,进行16位的反馈计算     while ( nleft > 1 ) {         sum += *w++;         nleft -= 2;     }     //补全奇数位     if ( nleft == 1 ) {         u_short u = 0;         *(u_char *)(&u) = *(u_char*)w;         sum += u;     }     //将反馈的16位从高位移到低位     sum = (sum >> 16) + (sum & 0xffff);     sum += (sum >> 16);     answer = ~sum;     return (answer); }  //发送回应请求函数 int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {     static ECHOREQUEST echoReq;     static int nId = 1;     static int nSeq = 1;     int nRet;     //填充回应请求消息     echoReq.icmpHdr.Type = ICMP_ECHOREQ;     echoReq.icmpHdr.Code = 0;     echoReq.icmpHdr.Checksum = 0;     echoReq.icmpHdr.ID = nId++;     echoReq.icmpHdr.Seq = nSeq++;     //填充要发送的数据     for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {         echoReq.cData[nRet] = '1' + nRet;     }     //存储发送的时间     echoReq.dwTime = timeGetTime();     //计算回应请求的校验和     echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));     //发送回应请求     nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),                   0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));     if (nRet == SOCKET_ERROR) {         printf("send to() error:%d\n", WSAGetLastError());     }     return (nRet); }  //接收应答回复并进行解析 DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {     ECHOREPLY echoReply;     int nRet;     int nAddrLen = sizeof(struct sockaddr_in);     //接收应答回复     nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),                     0,(LPSOCKADDR)lpsaFrom,&nAddrLen);     //检验接收结果      if (nRet == SOCKET_ERROR) {         printf("recvfrom() error:%d\n",WSAGetLastError());     }     //记录返回的TTL     *pTTL = echoReply.ipHdr.TTL;     //返回应答时间     return(echoReply.echoRequest.dwTime); }  //等待回应答复,使用select模型 int WaitForEchoReply(SOCKET s) {     struct timeval timeout;     fd_set readfds;     readfds.fd_count = 1;     readfds.fd_array[0] = s;     timeout.tv_sec = 1;     timeout.tv_usec = 0;     return(select(1, &readfds, NULL, NULL, &timeout)); }  //PING功能实现 void Ping(char *pstrHost,bool logic) {     SOCKET rawSocket;     LPHOSTENT lpHost;     struct sockaddr_in destIP;     struct sockaddr_in srcIP;     DWORD dwTimeSent;     DWORD dwElapsed;     u_char cTTL;     int nLoop,k=4;     int nRet,minimum=100000,maximum=0,average=0;     int sent=4,reveived=0,lost=0;     //创建原始套接字,ICMP类型     rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);     if (rawSocket == SOCKET_ERROR) {         printf("socket() error:%d\n", WSAGetLastError());         return;     }     //检测目标主机     lpHost = gethostbyname(pstrHost);     if (lpHost==NULL) {         printf("Host not found:%s\n", pstrHost);         return;     }     //设置目标机地址     destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //设置目标IP     destIP.sin_family = AF_INET;  //地址规格     destIP.sin_port = 0;     //提示开始进行PING     printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);     //发起多次PING测试     for (nLoop=0; nLoop<k; nLoop++) {         if (logic)k=k+1;         //发送ICMP回应请求         SendEchoRequest(rawSocket, &destIP);         //等待回复的数据         nRet = WaitForEchoReply(rawSocket);         if (nRet == SOCKET_ERROR) {             printf("select() error:%d\n", WSAGetLastError());             break;         }         if (!nRet) {             lost++;             printf("\nRequest time out.");             continue;         }         //接收回复         dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);         reveived++;         //计算花费的时间         dwElapsed = timeGetTime() - dwTimeSent;         if(dwElapsed>maximum)maximum=dwElapsed;         if(dwElapsed<minimum)minimum=dwElapsed;         average+=dwElapsed;         printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",                inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);     }     printf("\n\n");     printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));     printf("    Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",            sent,reveived,lost,(float)(lost*1.0/sent)*100);     if(lost==0) {         printf("Approximate round trip times in milli-seconds:\n");         printf("    Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);     }     printf("\n\n");     nRet = closesocket(rawSocket);     if (nRet == SOCKET_ERROR) {         printf("closesocket() error:%d\n", WSAGetLastError());     } }  void main() {     printf("Welcome to the Ping Test\n");     while(1) {         WSADATA wsd;//检测输入的参数         //初始化Winsock         if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {             printf("加载 Winsock 失败!\n");         }         char opt1[100];         char *ptr=opt1;         bool log=false;         printf("Ping ");         cin.getline(opt1,100,'\n');         if((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) { //          log=true;             ptr=opt1+3;         }         //开始PING         Ping(ptr,log);         //程序释放 Winsock 资源         WSACleanup();     } } //Welcome to the Ping Test //Ping -t www.baidu.com // //Pinging www.baidu.com [119.75.217.56] with 32 bytes of data: // //Reply from 119.75.217.56: bytes = 32 time = 4ms TTL = 51 //Reply from 119.75.217.56: bytes = 32 time = 2ms TTL = 51 //Reply from 119.75.217.56: bytes = 32 time = 2ms TTL = 51 //Reply from 119.75.217.56: bytes = 32 time = 2ms TTL = 51 // //Ping statistics for 119.75.217.56: //  Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), //Approximate round trip times in milli-seconds: //  Minimum = 2ms, Maximum = 4ms, Average = 2ms // // //Ping ^C

user: user-0
content: 引用 4 楼 zhao4zhong1 的回复:第241行：        if((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) 说明 你需要在显示Ping时输入“-t www.baidu.com” 不应将%ld替换为%I64d cmd里。ping百度的time在18ms左右，TTL在54ms左右。

user: user-0
content: 引用 4 楼 zhao4zhong1 的回复:第241行：        if((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) 说明 你需要在显示Ping时输入“-t www.baidu.com” 不应将%ld替换为%I64d 那样会不停的ping，而且获得的时间time比真实的大，ttl倒是蛮靠近真实值  你可以从结果看来，代码运行是错误的，我ping了百度，但返回的结果中间居然还参杂着我自己的ip。。哎，头疼。如果你能在你的机子上跑一下上面的代码，你就能知道它有多蛋疼了。。

user: user-1
content: 第241行：        if((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) 说明 你需要在显示Ping时输入“-t www.baidu.com” 不应将%ld替换为%I64d

user: user-0
content: 坐等大神。。

user: user-0
content: 引用 1 楼 zhao4zhong1 的回复:将%ld改为%I64d 你好，我将第208行按照你说的改了，结果运行结果变成下面那张图那样了，你能帮我看一下图片吗？我怀疑它根本就没有工作，因为结果是一下子都出来的，而不像我们在cmd上那样是一行一行出来。

user: user-1
content: 将%ld改为%I64d