ping的实现和代码分析
一.介紹 ? ??
ping命令是用來查看網(wǎng)絡(luò)上另一個(gè)主機(jī)系統(tǒng)的網(wǎng)絡(luò)連接是否正常的一個(gè)工具。ping命令的工作原理是:
向網(wǎng)絡(luò)上的另一個(gè)主機(jī)系統(tǒng)發(fā)送ICMP報(bào)文,如果指定系統(tǒng)得到了報(bào)文,它將把報(bào)文一模一樣地傳回給發(fā)送者,這有點(diǎn)象潛水艇聲納系統(tǒng)中使用的發(fā)聲裝置。 例如,在Linux終端上執(zhí)行ping如下:
二.分析
由上面的執(zhí)行結(jié)果可以看到,ping命令執(zhí)行后顯示出被測試系統(tǒng)主機(jī)名和相應(yīng)IP地址、返回給當(dāng)前主機(jī)的ICMP報(bào)文順序號、ttl生存時(shí)間和往返時(shí)間rtt(單位是毫秒,即千分之一秒)。要寫一個(gè)模擬ping命令,這些信息有啟示作用。要真正了解ping命令實(shí)現(xiàn)原理,就要了解ping命令所使用到的TCP/IP協(xié)議。 ICMP(Internet Control Message,網(wǎng)際控制報(bào)文協(xié)議)是為網(wǎng)關(guān)和目標(biāo)主機(jī)而提供的一種差錯(cuò)控制機(jī)制,使它們在遇到差錯(cuò)時(shí)能把錯(cuò)誤報(bào)告給報(bào)文源發(fā)方。ICMP協(xié)議是IP層的一個(gè)協(xié)議,但是由于差錯(cuò)報(bào)告在發(fā)送給報(bào)文源發(fā)方時(shí)可能也要經(jīng)過若干子網(wǎng),因此牽涉到路由選擇等問題,所以ICMP報(bào)文需通過IP協(xié)議來發(fā)送。ICMP數(shù)據(jù)報(bào)的數(shù)據(jù)發(fā)送前需要兩級封裝:首先添加ICMP報(bào)頭形成ICMP報(bào)文,再添加IP報(bào)頭形成IP數(shù)據(jù)報(bào)。由于IP層協(xié)議是一種點(diǎn)對點(diǎn)的協(xié)議,而非端對端的協(xié)議,它提供無連接的數(shù)據(jù)報(bào)服務(wù),沒有端口的概念,因此很少使用bind()和connect()函數(shù),若有使用也只是用于設(shè)置IP地址。明白了工作原理,我們就可以寫我們自己的ping命令:myping:
代碼1:
/*?????*????名稱:?????myping? *?????程序應(yīng)用:??ping命令是向目的主機(jī)發(fā)送ICMP報(bào)文,檢驗(yàn)本地主機(jī)和遠(yuǎn)程的目的主機(jī)是否連接? *??????*?? */?????/*ICMP必須使用原始套接字進(jìn)行設(shè)計(jì),要手動設(shè)置IP的頭部和ICMP的頭部并行校驗(yàn)*/?? /***********主函數(shù)*********************************************? myping.c*/?? #include?<sys/socket.h>?? #include?<netinet/in.h>?? #include?<netinet/ip.h>?? #include?<netinet/ip_icmp.h>?? #include?<unistd.h>?? #include?<signal.h>?? #include?<arpa/inet.h>?? #include?<errno.h>?? #include?<sys/time.h>?? #include?<stdio.h>?? #include?<string.h>?/*?bzero?*/?? #include?<netdb.h>?? #include?<pthread.h>?? //保存發(fā)送包的狀態(tài)值?? typedef?struct?pingm_pakcet{??struct?timeval?tv_begin;?????//發(fā)送時(shí)間??struct?timeval?tv_end;???????//接收到的時(shí)間??short?seq;???????????????????//序列號??int?flag;??????????//1,表示已經(jīng)發(fā)送但是沒有接收到回應(yīng),0,表示接收到回應(yīng)?? }pingm_pakcet;?? static?pingm_pakcet?*icmp_findpacket(int?seq);?? static?unsigned?short?icmp_cksum(unsigned?char?*data,?int?len);?? static?struct?timeval?icmp_tvsub(struct?timeval?end,?struct?timeval?begin);?? static?void?icmp_statistics(void);?? static?void?icmp_pack(struct?icmp?*icmph,?int?seq,?struct?timeval?*tv,int?length);?? static?int?icmp_unpack(char?*buf,int?len);?? static?void?*icmp_recv(void?*argv);?? static?void?icmp_sigint(int?signo);?? static?void?icmp_usage();???? static?pingm_pakcet?pingpacket[128];?? #define?K?1024?? #define?BUFFERSIZE?72????????????????????????????//發(fā)送緩沖區(qū)的大小?? static?unsigned?char?send_buff[BUFFERSIZE];???????? static?unsigned?char?recv_buff[2*K];?????????????//防止接收溢出,設(shè)置大一些?? static?struct?sockaddr_in?dest;??????????????????//目的地址?? static?int?rawsock?=?0;??????????????????????????//發(fā)送和接收線程需要的socket描述符?? static?pid_t?pid;????????????????????????????????//進(jìn)程PID?? static?int?alive?=?0;????????????????????????????//是否接收到退出信號?? static?short?packet_send?=?0;????????????????????//已經(jīng)發(fā)送的數(shù)據(jù)包數(shù)量?? static?short?packet_recv?=?0;????????????????????//已經(jīng)接收的數(shù)據(jù)包數(shù)量?? static?char?dest_str[80];????????????????????????//目的主機(jī)字符串?? static?struct?timeval?tv_begin,?tv_end,?tv_interval;??2.計(jì)算發(fā)送和接收的時(shí)間 static?void?icmp_usage()?? {??//ping加IP地址或者域名??printf("ping?aaa.bbb.ccc.ddd\n");?? }?? /*終端信號處理函數(shù)SIGINT*/?? static?void?icmp_sigint(int?signo)?? {??alive?=?0;??gettimeofday(&tv_end,NULL);??tv_interval?=?icmp_tvsub(tv_end,?tv_begin);????return;?? }?3.統(tǒng)計(jì)數(shù)據(jù)結(jié)果 /*統(tǒng)計(jì)數(shù)據(jù)結(jié)果函數(shù)******************************************? 打印全部ICMP發(fā)送的接收統(tǒng)計(jì)結(jié)果*/?? static?void?icmp_statistics(void)??{??long?time?=?(tv_interval.tv_sec?*?1000)?+?(tv_interval.tv_usec/1000);??printf("---?%s?ping?statistics?---\n",?dest_str);??printf("%d?packets?transmitted,?%d?received,?%d%c?packet?loss,?time?%ld?ms\n",???packet_send,packet_recv,(packet_send-packet_recv)*100/packet_send,'%',time);?? }??/*************查找數(shù)組中的標(biāo)識函數(shù)***********************?查找合適的包的位置? 當(dāng)seq為1時(shí),表示查找空包? 其他值表示查找seq對應(yīng)的包*/??static?pingm_pakcet?*icmp_findpacket(int?seq)??{??int?i;??pingm_pakcet?*found?=?NULL;??//查找包的位置??if(seq?==?-1){??for(i=0;i<128;i++){??if(pingpacket[i].flag?==?0){??found?=?&pingpacket[i];??break;??}??}??}??else?if(seq?>=?0){??for(i?=0?;i<?128;i++){??if(pingpacket[i].seq?==?seq){??found?=?&pingpacket[i];??break;??}??}??}??return?found;??}?4.校驗(yàn)和函數(shù) /*************校驗(yàn)和函數(shù)*****************************? TCP/IP協(xié)議棧使用的校驗(yàn)算法是比較經(jīng)典的,對16位的數(shù)據(jù)進(jìn)行累加計(jì)算,并返回計(jì)算結(jié)果,?CRC16校驗(yàn)和計(jì)算icmp_cksum? 參數(shù):?data:數(shù)據(jù)?len:數(shù)據(jù)長度? 返回值:?計(jì)算結(jié)果,short類型? */?? static?unsigned?short?icmp_cksum(unsigned?char?*data,?int?len)?? {??int?sum?=?0;???//計(jì)算結(jié)果??int?odd?=?len?&?0x01;??//是否為奇數(shù)??/*將數(shù)據(jù)按照2字節(jié)為單位累加起來*/??while(len?&?0xfffe){??sum?+=?*(unsigned?short*)data;??data?+=?2;??len?-=?2;??}??/*判斷是否為奇數(shù)個(gè)數(shù)據(jù),若ICMP報(bào)頭為奇數(shù)個(gè)字節(jié),會剩下最后一個(gè)字節(jié)*/??if(odd){??unsigned?short?tmp?=?((*data)<<8)&0xff00;??sum?+=?tmp;??}??sum?=?(sum?>>?16)?+?(sum?&?0xffff);???//高地位相加??sum?+=?(sum?>>?16);????????????????????//將溢出位加入??return?~sum;???????????????????????????//返回取反值?? }?5.ICMP頭部校驗(yàn)打包和拆包 /**********進(jìn)行ICMP頭部校驗(yàn)********************/?? //設(shè)置ICMP報(bào)頭?? static?void?icmp_pack(struct?icmp?*icmph,?int?seq,?struct?timeval?*tv,?int?length)?? {??unsigned?char?i?=?0;??//設(shè)置報(bào)頭??icmph->icmp_type?=?ICMP_ECHO;???//ICMP回顯請求??icmph->icmp_code?=?0;???????????//code的值為0??icmph->icmp_cksum?=?0;??????????//先將cksum的值填為0,便于以后的cksum計(jì)算??icmph->icmp_seq?=?seq;??????????//本報(bào)的序列號??icmph->icmp_id?=?pid?&?0xffff;??//填寫PID??for(i=0;?i<?length;?i++)??icmph->icmp_data[i]?=?i;???//計(jì)算校驗(yàn)和??icmph->icmp_cksum?=?icmp_cksum((unsigned?char*)icmph,?length);?? }??/*解壓接收到的包,并打印信息*/?? static?int?icmp_unpack(char?*buf,?int?len)?? {??int?i,iphdrlen;??struct?ip?*ip?=?NULL;??struct?icmp?*icmp?=?NULL;??int?rtt;??ip?=?(struct?ip?*)buf;????????????//IP報(bào)頭??iphdrlen?=?ip->ip_hl?*?4;?????????//IP頭部長度??icmp?=?(struct?icmp?*)(buf+iphdrlen);??//ICMP段的地址??len?-=?iphdrlen;??//判斷長度是否為ICMP包??if(len?<?8){??printf("ICMP?packets\'s?length?is?less?than?8\n");??return?-1;??}??//ICMP類型為ICMP_ECHOREPLY并且為本進(jìn)程的PID??if((icmp->icmp_type?==?ICMP_ECHOREPLY)?&&?(icmp->icmp_id?==?pid)){??struct?timeval?tv_interval,tv_recv,tv_send;??//在發(fā)送表格中查找已經(jīng)發(fā)送的包,按照seq??pingm_pakcet?*packet?=?icmp_findpacket(icmp->icmp_seq);??if(packet?==?NULL)??return?-1;??packet->flag?=?0;??????????//取消標(biāo)志??tv_send?=?packet->tv_begin;??//獲取本包的發(fā)送時(shí)間??gettimeofday(&tv_recv,NULL);??//讀取此時(shí)間,計(jì)算時(shí)間差??tv_interval?=?icmp_tvsub(tv_recv,tv_send);??rtt?=?tv_interval.tv_sec?*?1000?+?tv_interval.tv_usec/1000;??/*打印結(jié)果包含?ICMP段的長度?源IP地址?包的序列號?TTL?時(shí)間差?*/??printf("%d?byte?from?%s:?icmp_seq=%u?ttl=%d?rtt=%d?ms\n",???len,inet_ntoa(ip->ip_src),icmp->icmp_seq,ip->ip_ttl,rtt);??packet_recv?++;??????????????//接收包數(shù)量加1??}??else?{??return?-1;??}?? }6.計(jì)算時(shí)間差函數(shù) /************計(jì)算時(shí)間差time_sub************************? 參數(shù):?end:接收到時(shí)間?begin:開始發(fā)送的時(shí)間? 返回值:?使用的時(shí)間? */?? static?struct?timeval?icmp_tvsub(struct?timeval?end,?struct?timeval?begin)?? {??struct?timeval?tv;??//計(jì)算差值??tv.tv_sec?=?end.tv_sec?-?begin.tv_sec;??tv.tv_usec?=?end.tv_usec?-?begin.tv_usec;??//如果接收的時(shí)間的usec值小于發(fā)送時(shí)的usec,從uesc域借位??if(tv.tv_usec?<?0){??tv.tv_sec?--;??tv.tv_usec?+=?1000000;??}??return?tv;?? }?7.發(fā)送報(bào)文函數(shù) //**********發(fā)送報(bào)文***************************?? static?void?*icmp_send(void?*argv)?? {??//保存程序開始發(fā)送數(shù)據(jù)的時(shí)間??gettimeofday(&tv_begin,?NULL);??while(alive){??int?size?=?0;??struct?timeval?tv;??gettimeofday(&tv,?NULL);?????//當(dāng)前包的發(fā)送時(shí)間??//在發(fā)送包狀態(tài)數(shù)組中找到一個(gè)空閑位置??pingm_pakcet?*packet?=?icmp_findpacket(-1);??if(packet){??packet->seq?=?packet_send;??packet->flag?=?1;??gettimeofday(&packet->tv_begin,NULL);??}??icmp_pack((struct?icmp?*)send_buff,packet_send,&tv,?64);??//打包數(shù)據(jù)??size?=?sendto(rawsock,?send_buff,64,0,(struct?sockaddr?*)&dest,?sizeof(dest));??if(size?<?0){??perror("sendto?error");??continue;??}??packet_send?++;??//每隔1s發(fā)送一個(gè)ICMP回顯請求包??sleep(1);??}?? }8.接收目的主機(jī)的回復(fù)函數(shù) /***********接收ping目的主機(jī)的回復(fù)***********?/? static?void?*icmp_recv(void?*argv)?? {??//輪詢等待時(shí)間??struct?timeval?tv;??tv.tv_usec?=?200;??tv.tv_sec?=?0;??fd_set?readfd;??//當(dāng)沒有信號發(fā)出一直接收數(shù)據(jù)??while(alive){??int?ret?=?0;??FD_ZERO(&readfd);??FD_SET(rawsock,&readfd);??ret?=?select(rawsock+1,&readfd,NULL,NULL,&tv);??switch(ret)??{??case?-1:??//錯(cuò)誤發(fā)生??break;??case?0:??//超時(shí)??break;??default?:??{??//收到一個(gè)包??int?fromlen?=?0;??struct?sockaddr?from;??//接收數(shù)據(jù)??int?size?=?recv(rawsock,recv_buff,sizeof(recv_buff),0);??if(errno?==?EINTR){??perror("recvfrom?error");??continue;??}??//解包??ret?=?icmp_unpack(recv_buff,size);??if(ret?==?1){??continue;??}??}??break;??}??}?? }?9.設(shè)置ICMP頭部(程序中不需要,這里只是作為了解) /**********設(shè)置ICMP發(fā)送報(bào)文的頭部*********************************?回顯請求的ICMP報(bào)文?*/?? /*struct?icmp? {?u_int8_t?icmp_type;???//消息類型?u_int8_t?icmp_code;???//消息類型的子碼?u_int16_t?icmp_cksum;???//校驗(yàn)和?union?{?struct?ih_idseq????//顯示數(shù)據(jù)報(bào)?{?u_int16_t?icd_id;??//數(shù)據(jù)報(bào)ID?u_int16_t?icd_seq;??//數(shù)據(jù)報(bào)的序號?}ih_idseq;???}icmp_hun;? #define?icmp_id?icmp_hun.ih_idseq.icd_id;? #define?icmp_seq?icmp_hun.ih_idseq.icd_seq;?union?{?u_int8_t?id_data[1];????//數(shù)據(jù)?}icmp_dun;? #define?icmp_data?icmp_dun.id_data;? };?*/10.主函數(shù) //主程序?? int?main(int?argc,?char?const?*argv[])?? {??struct?hostent?*host?=?NULL;??struct?protoent?*protocol?=?NULL;??char?protoname[]?=?"icmp";??unsigned?long?inaddr?=?1;??int?size?=?128*K;??if(argc?<?2)?????????????????????//參數(shù)是否數(shù)量正確??{??icmp_usage();??return?-1;??}??//獲取協(xié)議類型??protocol?=?getprotobyname(protoname);??if(protocol?==?NULL)??{??perror("getprotobyname()");??return?-1;??}??//復(fù)制目的地址字符串??memcpy(dest_str,?argv[1],strlen(argv[1])+1);??memset(pingpacket,?0,?sizeof(pingm_pakcet)?*?128);??//socket初始化??rawsock?=?socket(AF_INET,?SOCK_RAW,?protocol->p_proto);??if(rawsock?<?0){??perror("socket");??return?-1;??}??pid?=?getuid();???????????????????????//為與其他線程區(qū)別,加入pid??//增大接收緩沖區(qū),防止接收包被覆蓋??setsockopt(rawsock,?SOL_SOCKET,?SO_RCVBUF,?&size,?sizeof(size));??bzero(&dest,?sizeof(dest));??//獲取目的地址的IP地址??dest.sin_family?=?AF_INET;??//輸入的目的地址為字符串IP地址??inaddr?=?inet_addr(argv[1]);??if(inaddr?==?INADDR_NONE){?????????????//輸入的是DNS地址??host?=?gethostbyname(argv[1]);??if(host?==?NULL){??perror("gethostbyname");??return?-1;??}??//將地址復(fù)制到dest??memcpy((char?*)&dest.sin_addr,?host->h_addr,?host->h_length);??}???????????????????????????????????????//IP地址字符串??else?{??memcpy((char?*)&dest.sin_addr,?&inaddr,sizeof(inaddr));??}??//打印提示??inaddr?=?dest.sin_addr.s_addr;??printf("PING?%s?(%ld.%ld.%ld.%ld)?56(84)?bytes?of?data.\n",???dest_str,(inaddr&0x000000ff)>>0,(inaddr&0x0000ff00)>>8,(inaddr&0x00ff0000)>>16,(inaddr&0xff000000)>>24);??//截取信號SIGINT,將icmp_sigint掛接上??signal(SIGINT,icmp_sigint);??/*發(fā)送數(shù)據(jù)并接收回應(yīng)?建立兩個(gè)線程,一個(gè)用于發(fā)數(shù)據(jù),另一個(gè)用于接收響應(yīng)數(shù)據(jù),主程序等待兩個(gè)線程運(yùn)行完畢后再進(jìn)行?下一步,最后對結(jié)果進(jìn)行統(tǒng)計(jì)并打印?*/??alive?=?1;?????????????????????????????????????//初始化可運(yùn)行??pthread_t?send_id,?recv_id;????????????????????//建立兩個(gè)線程,用于發(fā)送和接收??int?err?=?0;??err?=?pthread_create(&send_id,?NULL,?icmp_send,?NULL);?//發(fā)送??if(err?<??0){??return?-1;??}??err?=?pthread_create(&recv_id,?NULL,?icmp_recv,?NULL);?//接收??if(err?<?0){??return?-1;??}??//等待線程結(jié)束??pthread_join(send_id,?NULL);??pthread_join(recv_id,?NULL);??//清理并打印統(tǒng)計(jì)結(jié)果??close(rawsock);??icmp_statistics();??return?0;?? }?三.程序運(yùn)行方法由于在程序中用到了<pthread.h>多線程,所以在編譯時(shí)要加上-lpthread,并且想要運(yùn)行的話要在root權(quán)限下,一般的用戶是沒有權(quán)限的此程序編譯方法為:
gcc -o myping myping.c -lpthread?
./myping www.baidu.com
結(jié)果為:
代碼2:
#include "stdafx.h" #include<stdio.h> #include<windows.h> #include<process.h>#pragma comment( lib, "ws2_32.lib" )#define SEND_SIZE 32 #define PACKET_SIZE 4096 #define ICMP_ECHO 8 #define ICMP_ECHOREPLY 0struct icmp {unsigned char icmp_type;unsigned char icmp_code;unsigned short icmp_cksum;unsigned short icmp_id;unsigned short icmp_seq;unsigned long icmp_data; };struct ip {unsigned char ip_hl:4; unsigned char ip_v:4; unsigned char ip_tos; unsigned short ip_len; unsigned short ip_id; unsigned short ip_off; unsigned char ip_ttl; unsigned char ip_p; unsigned short ip_sum; unsigned long ip_src;unsigned long ip_dst; };/*unsigned */char sendpacket[PACKET_SIZE]; /*unsigned */char recvpacket[PACKET_SIZE]; struct sockaddr_in dest_addr; struct sockaddr_in from_addr; int sockfd; int pid;unsigned short cal_chksum(unsigned short *addr,int len); int pack(int pack_no); int unpack(/*unsigned*/ char *buf,int len); void send_packet(void); void recv_packet(void);void main(int argc,char *argv[]) { struct hostent *host;struct protoent *protocol;WSADATA wsaData;int timeout=1000;int SEND_COUNT=4;int i;char* par_host = "www.baidu.com";/*par_host=argv[argc-1];switch(argc){case 2: break;case 3: if(strcmp(argv[1],"-t")==0){SEND_COUNT=10000;break;}//fall throughdefault:printf("usage: %s [-t] Host name or IP address\n",argv[0]);exit(1); }*/if(WSAStartup(0x1010,&wsaData)!=0){printf("wsastartup error\n");exit(1);}if( (protocol=getprotobyname("icmp") )==NULL){printf("getprotobyname error\n");exit(1);}if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0){ printf("socket error\n");exit(1);}if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout))<0) fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());if(setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout))<0)fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError()); memset(&dest_addr,0,sizeof(dest_addr));dest_addr.sin_family=AF_INET;if(host=gethostbyname(par_host) ){memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length);//resolve address to hostnameif(host=gethostbyaddr(host->h_addr,4,PF_INET))par_host=host->h_name;}else if( dest_addr.sin_addr.s_addr=inet_addr(par_host)==INADDR_NONE){printf("Unkown host %s\n",par_host);exit(1);}pid = _getpid();printf("Pinging %s [%s]: with %d bytes of data:\n\n",par_host,inet_ntoa(dest_addr.sin_addr),SEND_SIZE); for(i=0;i<SEND_COUNT;i++) {send_packet();recv_packet();Sleep(1000);} }//this algorithm is referenced from other's unsigned short cal_chksum(unsigned short *addr,int len)d //打包 int pack(int pack_no) { int packsize;struct icmp *icmp;packsize=8+SEND_SIZE;icmp=(struct icmp*)sendpacket;icmp->icmp_type=ICMP_ECHO;icmp->icmp_code=0;icmp->icmp_cksum=0;icmp->icmp_seq=pack_no;icmp->icmp_id=pid;icmp->icmp_data=GetTickCount();icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize); /*校驗(yàn)算法*/return packsize; }//解包 int unpack(/*unsigned*/ char *buf,int len) { struct ip *ip;struct icmp *icmp;double rtt;int iphdrlen;ip=(struct ip *)buf;iphdrlen=ip->ip_hl*4; icmp=(struct icmp *)(buf+iphdrlen); if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) ){len=len-iphdrlen-8; rtt=GetTickCount()-icmp->icmp_data; printf("Reply from %s: bytes=%d time=%.0fms TTL=%d icmp_seq=%u\n", inet_ntoa(from_addr.sin_addr),len,rtt,ip->ip_ttl,icmp->icmp_seq);return 1;}return 0; }//發(fā)送 void send_packet() { int packetsize;static int pack_no=0;packetsize=pack(pack_no++);if( sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0 )printf("Destination host unreachable.\n");// printf("send NO %d\n",pack_no-1); }//接收 void recv_packet() { int n,fromlen;int success;fromlen=sizeof(from_addr);do{if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from_addr,&fromlen)) >=0)success=unpack(recvpacket,n);else if (WSAGetLastError() == WSAETIMEDOUT){printf("Request timed out.\n");return;}}while(!success);}gcc -o myping myping.c -lpthread ./myping www.baidu.com
gcc -o myping myping.c -lpthread ./myping www.baidu.com
總結(jié)
以上是生活随笔為你收集整理的ping的实现和代码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QQ采用什么传输协议?
- 下一篇: 嵌入式处理器的体系架构与内核详解