![ping命令的設(shè)計(jì)與實(shí)現(xiàn)_第1頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/7/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d1.gif)
![ping命令的設(shè)計(jì)與實(shí)現(xiàn)_第2頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/7/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d2.gif)
![ping命令的設(shè)計(jì)與實(shí)現(xiàn)_第3頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/7/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d3.gif)
![ping命令的設(shè)計(jì)與實(shí)現(xiàn)_第4頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/7/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d4.gif)
![ping命令的設(shè)計(jì)與實(shí)現(xiàn)_第5頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/7/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d/3e52b274-c7ec-4cac-b1d2-b4ae7c40121d5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、設(shè)計(jì)報(bào)告課 程 計(jì)算機(jī)網(wǎng)絡(luò) 設(shè)計(jì)名稱 ping命令的設(shè)計(jì)與實(shí)現(xiàn) 專業(yè)班級(jí) 計(jì)科094 同組人姓名 同組人學(xué)號(hào) 實(shí)驗(yàn)日期 2013-04-10 指導(dǎo)教師 成 績(jī) 2013 年 04 月 10 日設(shè)計(jì)目的和要求1、實(shí)驗(yàn)?zāi)康模篜ing命令向目的主機(jī)發(fā)送ICMP ECHOREQUEST請(qǐng)求并接收目的主機(jī)返回的響應(yīng)報(bào)文,用來檢驗(yàn)本地主機(jī)和遠(yuǎn)程的主機(jī)是否連接。2.實(shí)驗(yàn)要求:利用ICMP數(shù)據(jù)包,測(cè)試主機(jī)的連通性,通過課程設(shè)計(jì),使學(xué)生熟悉ICMP報(bào)文結(jié)構(gòu),使學(xué)生對(duì)ICMP有更深的理解。要求:輸出參考系統(tǒng)自帶ping程序,命令行運(yùn)行:ping ip二、設(shè)計(jì)說明設(shè)計(jì)分析:使用原始套接字可以讀寫ICMP分組,利用原
2、始套接字發(fā)送ICMP回顯請(qǐng)求,并接收ICMP回顯應(yīng)答,通過icmp_send()發(fā)送ICMP回顯示請(qǐng)求包,icmp_recv() 接收ping目的主機(jī)的回復(fù),并使用終端信號(hào)處理函數(shù)SIGINT處理信號(hào),建立兩個(gè)線程,一個(gè)用于發(fā)送數(shù)據(jù),另一個(gè)用于接收響應(yīng)數(shù)據(jù),主程序等待兩個(gè)線程運(yùn)行完畢后再進(jìn)行下一步動(dòng)作。最后,主程序講發(fā)送數(shù)據(jù)和接收的數(shù)據(jù)進(jìn)行統(tǒng)計(jì),并將結(jié)果打印出來。系統(tǒng)運(yùn)行環(huán)境:虛擬機(jī):Fedora14(linux操作系統(tǒng)) gcc設(shè)計(jì)中的重點(diǎn)和難點(diǎn):ICMP數(shù)據(jù)包的打包和解包,以及從CRC16校驗(yàn)算法的分析實(shí)現(xiàn)輸入和輸出條件:在linux系統(tǒng)下運(yùn)行ping 在出現(xiàn)4個(gè)響應(yīng)包后按Ctrl+c鍵停
3、止發(fā)送。 三、系統(tǒng)詳細(xì)設(shè)計(jì) Ping命令的設(shè)計(jì)與實(shí)現(xiàn) Ping命令向目的主機(jī)發(fā)送ICMP ECHOREQUEST請(qǐng)求并接收目的主機(jī)返回的響應(yīng)報(bào)文,用來檢驗(yàn)本地主機(jī)和遠(yuǎn)程的主機(jī)是否連接。n 協(xié)議格式圖1.1中已經(jīng)對(duì)協(xié)議的報(bào)文格式進(jìn)行了說明。Ping 的客戶端方式的類型為8,代碼值為0,表示ICMP的回顯請(qǐng)求。類型為0,代碼為0是,是ICMP回顯應(yīng)答。檢驗(yàn)和為16為的 crc16 的算法。0 7 8 15 16 31類型(8位)代碼(8位)校驗(yàn)和(16位)此部分不同的類型和代碼格式不同 圖 1.1 ICMP報(bào)文的數(shù)據(jù)格式圖1.2所示為 ping所使用的類型和代碼格式。包含16位的標(biāo)始符和16為的序
4、列號(hào)。序列號(hào)是用于標(biāo)識(shí)發(fā)送或者響應(yīng)的序號(hào),而標(biāo)示符通常用于表明發(fā)送和接收此報(bào)的用戶,一眼用進(jìn)程的PID來識(shí)別。0 7 8 15 16 31類型(8或0)代碼(0)校驗(yàn)和標(biāo)示符序列符占位字節(jié)圖1.2 ping的數(shù)據(jù)格式例如一個(gè)用戶的進(jìn)程PID為1000,發(fā)送了一個(gè)序列號(hào)為1的回顯請(qǐng)求報(bào)文,當(dāng)此報(bào)文被目的主機(jī)正確處理并返回后,可以用PID來識(shí)別是否為當(dāng)前的用戶,并且用序列號(hào)來識(shí)別哪個(gè)報(bào)文被返回,通過發(fā)送報(bào)文到目的主機(jī)并接受響應(yīng),可以計(jì)算發(fā)送和接收二者之間的時(shí)間差,來判斷網(wǎng)絡(luò)的狀況。如圖1.3所示,ping程序一般按照?qǐng)D中的框架進(jìn)行設(shè)計(jì)。主要分為發(fā)送數(shù)據(jù)和接收數(shù)據(jù)及計(jì)算時(shí)間差。發(fā)送數(shù)據(jù)對(duì)組織好的數(shù)據(jù)
5、進(jìn)行發(fā)送,接收數(shù)據(jù)從網(wǎng)絡(luò)上接收數(shù)據(jù)并判斷其合法性,例如判斷是否本進(jìn)程發(fā)出的報(bào)文等。開始設(shè)置發(fā)送數(shù)據(jù)計(jì)算機(jī)發(fā)送數(shù)據(jù)校驗(yàn)和發(fā)送數(shù)據(jù)接收數(shù)據(jù)計(jì)算時(shí)速差解包判斷正誤結(jié)束圖1.3 ping程序的基本框架由于ICMP必須使用原始套接字進(jìn)行設(shè)計(jì),要手動(dòng)設(shè)置IP的頭部和ICMP的頭部并進(jìn)行校驗(yàn)。n 校驗(yàn)和函數(shù)TCP/IP 協(xié)議棧使用的校驗(yàn)算法是比較經(jīng)典的,對(duì)16為的數(shù)據(jù)進(jìn)行累加計(jì)算,并返回計(jì)算結(jié)果。需要注意的是對(duì)奇數(shù)個(gè)字節(jié)數(shù)據(jù)的計(jì)算,是將最后的有效數(shù)據(jù)作為最高位的字節(jié),低字節(jié)填充了0。/* CRC16校驗(yàn)和計(jì)算icmp_cksum參數(shù):data:數(shù)據(jù)len:數(shù)據(jù)長(zhǎng)度返回值:計(jì)算結(jié)果,short類型*/stat
6、ic unsigned short icmp_cksum(unsigned char *data, int len) int sum=0;/* 計(jì)算結(jié)果 */int odd = len & 0x01;/*是否為奇數(shù)*/unsigned short *value = (unsigned short*)data;/*將數(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é),會(huì)剩下最后一字節(jié)。*/ if( odd)
7、 unsigned short tmp = (*data)<<8)&0xff00; sum += tmp; sum = (sum >>16) + (sum & 0xffff); sum += (sum >>16) ; return sum;n 設(shè)置IP發(fā)送報(bào)文的頭部ip頭部格式:struct ip#if _BYTE_ORDER = _LITTLE_ENDIAN /* 如果為小端 */gned int ip_v:4;/* 版本 */#endif#if _BYTE_ORDER = _BIG_ENDIAN /*如果為大端*/unsigned int
8、 ip_v:4;/* 版本 */unsigned int ip_hl:4;/* 頭部長(zhǎng)度 */#endifu_int8_t ip_tos;/* TOS,服務(wù)類型 */u_short ip_len;/* 總長(zhǎng)度 */u_short ip_id;/* 標(biāo)識(shí)值 */u_short ip_off;* 段偏移值 */u_int8_t ip_ttl;/* TTL,生存時(shí)間 */u_int8_t ip_p;/* 協(xié)議類型 */u_short ip_sum;/* 校驗(yàn)和 */struct in_addr ip_src, ip_dst;/* 源地址和目的地址 */;n 設(shè)置ICMP發(fā)送報(bào)文的頭部對(duì)于回顯請(qǐng)求的I
9、CMP報(bào)文,下面是ICMP結(jié)構(gòu)簡(jiǎn)化形式:struct icmpu_int8_t icmp_type;/* 消息類型 */u_int8_t icmp_code;/* 消息類型的子碼 */u_int16_t icmp_cksum;/* 校驗(yàn)和 */ union u_char ih_pptr;/* ICMP_PARAMPROB */ struct in_addr ih_gwaddr;/* 網(wǎng)關(guān)地址 */ 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)的序號(hào) */ ih_idseq; ic
10、mp_hun; #define icmp_idicmp_hun.ih_idseq.icd_id#define icmp_seq icmp_hun.ih_idseq.icd_seq union struct u_int8_t id_data1;/* 數(shù)據(jù) */ icmp_dun;#defineicmp_dataicmp_dun.id_data;即僅包含消息類型、消息代碼、校驗(yàn)和、數(shù)據(jù)報(bào)的ID、數(shù)據(jù)報(bào)的序列號(hào)即ICMP數(shù)據(jù)段幾個(gè)部分。校驗(yàn)和的值在計(jì)算之前其他的值應(yīng)該先進(jìn)行填充,而校驗(yàn)和也需要設(shè)置為0來占位,然后在計(jì)算真正的校驗(yàn)和值。ICMP回顯得數(shù)據(jù)部分可以任意設(shè)置,但是以太網(wǎng)包的總長(zhǎng)度不能小于以
11、太網(wǎng)的最小值,即總長(zhǎng)度不能小于46,由于IP頭部為20字節(jié),ICMP頭部為8個(gè)字節(jié),以太網(wǎng)頭部占用14個(gè)字節(jié),因此ICMP回顯包的最小值為46-20-8-14=4個(gè)字節(jié)。Ø ICMP回顯請(qǐng)求的類型為8,即ICMP-ECHO。Ø ICMP回顯請(qǐng)求的代碼值為0.Ø ICMP回顯請(qǐng)求的序列號(hào)是一個(gè)16位的值,通常由一個(gè)遞增的值生成。Ø ICMP回顯請(qǐng)求的ID用于區(qū)別,通常用進(jìn)程的PID填充。進(jìn)行ICMP頭部校驗(yàn)的代碼如下:/*設(shè)置ICMP報(bào)頭*/static void icmp_pack(struct icmp *icmph, int seq, struct
12、timeval *tv, int length ) unsigned char i = 0;/* 設(shè)置報(bào)頭 */icmph->icmp_type = ICMP_ECHO;/*ICMP回顯請(qǐng)求*/icmph->icmp_code = 0;/*code值為0*/icmph->icmp_cksum = 0;/*先將cksum值填寫0,便于之后的cksum計(jì)算*/icmph->icmp_seq = seq;/*本報(bào)的序列號(hào)*/icmph->icmp_id = pid &0xffff;/*填寫PID*/for(i = 0; i< length; i+)icmp
13、h->icmp_datai = i;/* 計(jì)算校驗(yàn)和 */icmph->icmp_cksum = icmp_cksum(unsigned char*)icmph, length);n 剝離ICMP接受報(bào)文的頭部函數(shù)icmp_unpack()用于剝離IP頭部,分析ICMP頭部的值。判斷是否為正確的ICMP報(bào)文,并打印結(jié)果。參數(shù)buf為剝?nèi)チ艘蕴W(wǎng)部分?jǐn)?shù)據(jù)的IP數(shù)據(jù)報(bào)文,len為數(shù)據(jù)長(zhǎng)度。可以利用IP頭部的參數(shù)快速地跳ICMP報(bào)文部分,IP結(jié)構(gòu)的ip_hl標(biāo)識(shí)IP頭部的長(zhǎng)度,由于ip_hl標(biāo)識(shí)的是4字節(jié)單位,所以需要乘以4來獲得ICMP段的地址。獲得ICMP數(shù)據(jù)段后,判斷其類型是否為I
14、CMP_ECHOREPLY,并核實(shí)其標(biāo)識(shí)是否為本進(jìn)程的PID。由于需要判斷數(shù)據(jù)報(bào)文的往返時(shí)間,在本程序中需要先查找這個(gè)包發(fā)送時(shí)的時(shí)間,與當(dāng)前時(shí)間進(jìn)行計(jì)算后,可以得出本地主機(jī)與目標(biāo)主機(jī)之間網(wǎng)絡(luò)ICMP回顯報(bào)文的差值。程序需要累加成功接收到的報(bào)文用于程序退出時(shí)的統(tǒng)計(jì)。/* 解壓接收到的包,并打印信息 */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頭部 */iphdrle
15、n=ip->ip_hl*4;/* IP頭部長(zhǎng)度 */icmp=(struct icmp *)(buf+iphdrlen);/* ICMP段的地址 */len-=iphdrlen;if( len<8) /* 判斷長(zhǎng)度是否為ICMP包 */ printf("ICMP packets's length is less than 8n");return -1;/* ICMP類型為ICMP_ECHOREPLY并且為本進(jìn)程的PID */if( (icmp->icmp_type=ICMP_ECHOREPLY) && (icmp->icmp_
16、id= pid) )struct timeval tv_internel,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í)時(shí)間,計(jì)算時(shí)間差 */tv_inte
17、rnel = icmp_tvsub(tv_recv,tv_send); rtt = tv_internel.tv_sec*1000+tv_internel.tv_usec/1000; /* 打印結(jié)果,包含* ICMP段長(zhǎng)度 源IP地址 包的序列號(hào) TTL 時(shí)間差*/printf("%d byte from %s: icmp_seq=%u ttl=%d rtt=%d msn",len,inet_ntoa(ip->ip_src),icmp->icmp_seq,ip->ip_ttl,rtt );packet_recv +;/* 接收包數(shù)量加1 */elseret
18、urn -1;函數(shù)的返回值為-1時(shí)表示褚翠,其他值則正常。n 計(jì)算時(shí)間差由于需要評(píng)估網(wǎng)絡(luò)狀況,在發(fā)送數(shù)據(jù)報(bào)文的時(shí)候保存發(fā)送時(shí)間,接收到報(bào)文后,計(jì)算兩個(gè)時(shí)刻之間的差值,生成了ICMP源主機(jī)和目標(biāo)主機(jī)之間的網(wǎng)絡(luò)狀況的時(shí)間評(píng)估。/*計(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;
19、tv.tv_usec = end.tv_usec - begin.tv_usec;/* 如果接收時(shí)間的usec值小于發(fā)送時(shí)的usec值,從usec域借位 */if(tv.tv_usec < 0)tv.tv_sec -;tv.tv_usec += 1000000; return tv;n 發(fā)送報(bào)文發(fā)送報(bào)文函數(shù)是一個(gè)線程,每隔1s向目的主機(jī)發(fā)送一個(gè)ICMP回顯請(qǐng)求報(bào)文,它在整個(gè)程序處于激活狀態(tài)(alive為1)是一直發(fā)送報(bào)文。(1) 獲得當(dāng)前的時(shí)間值,按照序列號(hào)packet_send將ICMP報(bào)文打包到緩沖區(qū)send_buff中后,發(fā)送到目的地址。發(fā)送成功后,記錄發(fā)送報(bào)文的狀態(tài):Ø
20、 序號(hào)seq 為packet_send。Ø 標(biāo)志flag為1,表示已經(jīng)發(fā)送但是沒有收到響應(yīng)。Ø 發(fā)送時(shí)間為之前獲得的時(shí)間。(2) 每次發(fā)送成功后序號(hào)值會(huì)增加1,即packet_send+.(3) 在線程開始進(jìn)入主循環(huán)while(alive)之前,將整個(gè)程序的開始發(fā)送時(shí)間記錄下來,用于在程序退出的時(shí)候進(jìn)行全局統(tǒng)計(jì),即gettimeofday(&tv_begin, NULL),j將時(shí)間保存在變量tv_begin 中。/* 發(fā)送ICMP回顯請(qǐng)求包 */static void * icmp_send(void *argv)struct timeval tv;tv.tv_us
21、ec = 0;tv.tv_sec = 1;gettimeofday(&tv_begin, NULL); /* 保存程序開始發(fā)送數(shù)據(jù)的時(shí)間 */while(alive)int size = 0;struct timeval tv;gettimeofday(&tv, NULL); /*當(dāng)前包的發(fā)送時(shí)間*/icmp_pack(struct icmp *)send_buff, packet_send, &tv, 64 ); /*打包數(shù)據(jù)*/ size = sendto (rawsock, send_buff, 64, 0,(struct sockaddr *)&dest
22、, sizeof(dest) ); /*將數(shù)據(jù)由指定的socket發(fā)送給目的地址*/if(size <0)perror("sendto error");continue;else/* 在發(fā)送包狀態(tài)數(shù)組中找一個(gè)空閑位置 */pingm_pakcet *packet = icmp_findpacket(-1);if(packet)packet->seq = packet_send;/* 設(shè)置seq */packet->flag = 1;/* 已經(jīng)使用 */gettimeofday( &packet->tv_begin, NULL);/* 發(fā)送時(shí)間
23、 */packet_send +;/* 計(jì)數(shù)增加 */sleep(1);/* 每隔一秒,發(fā)送一個(gè)ICMP回顯請(qǐng)求包 */n 接收?qǐng)?bào)文與發(fā)送函數(shù)一樣,接收?qǐng)?bào)文也用一個(gè)線程實(shí)現(xiàn),使用select()輪詢等待報(bào)文到來。當(dāng)接收到一個(gè)報(bào)文后使用函數(shù)icmp_unpack()來解包和查找報(bào)文之前發(fā)送時(shí)的記錄,獲取發(fā)送時(shí)間,計(jì)算收發(fā)差值并打印信息。(1) 接收成功后將合法的報(bào)文記錄重置為沒有使用,flag為0.。(2) 接收?qǐng)?bào)文數(shù)量增加1.(3) 為了防止丟包,select()輪詢時(shí)間設(shè)置的比較短。/* 接收ping目的主機(jī)的回復(fù) */static void *icmp_recv(void *argv)/*
24、 輪訓(xùn)等待時(shí)間 */struct timeval tv;tv.tv_usec = 200;tv.tv_sec = 0;fd_set readfd;/* 當(dāng)沒有信號(hào)發(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:break; /* 超時(shí) */default: /* 收到一個(gè)包 *
25、/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); /* 解包并設(shè)置相關(guān)變量 */if(ret = -1)continue;break;n 主函數(shù)過程Ping程序的實(shí)現(xiàn)使用了兩個(gè)線程,一個(gè)線程 icmp_send()用于發(fā)送請(qǐng)求,一個(gè)線程icmp
26、_recv()用于接收遠(yuǎn)程主機(jī)的響應(yīng)。當(dāng)變量alive為0時(shí),兩個(gè)線程退出。1. ping數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu) 類型為結(jié)構(gòu)struct pingm_packet的變量pingpacket用于保存發(fā)送數(shù)據(jù)報(bào)文的狀態(tài):Ø tv_begin 用于保存發(fā)送的時(shí)間。Ø tv_end 用于保存數(shù)據(jù)報(bào)文接收到的時(shí)間。Ø seq是序列號(hào),用于標(biāo)識(shí)報(bào)文,作為索引。Ø flag用于表示本單元的狀態(tài),1表示數(shù)據(jù)報(bào)文已經(jīng)發(fā)送,但是沒有收到回應(yīng)包; 0表示已經(jīng)接收到回應(yīng)報(bào)文,這個(gè)單元可以再次用于標(biāo)識(shí)發(fā)送的報(bào)文。/* 保存已經(jīng)發(fā)送包的狀態(tài)值 */typedef struct pingm_
27、pakcetstruct timeval tv_begin;/*發(fā)送的時(shí)間*/struct timeval tv_end;/*接收到的時(shí)間*/short seq;/*序列號(hào)*/int flag;/*1,表示已經(jīng)發(fā)送但沒有接收到回應(yīng)包0,表示接收到回應(yīng)包*/pingm_pakcet;static pingm_pakcet pingpacket128;2. SIGINT處理函數(shù)本程序借去了信號(hào) SIGINT,用函數(shù)icmp_sigint() 對(duì)SIGINT進(jìn)行處理。當(dāng)用戶按下Ctrl+C鍵時(shí),將alive設(shè)置為0,使得接收和發(fā)送兩個(gè)線程退出,并計(jì)算結(jié)束時(shí)的時(shí)間。代碼如下:/* 終端信號(hào)處理函數(shù)SI
28、GINT */static void icmp_sigint(int signo)/* 告訴接收和發(fā)送線程結(jié)束程序 */alive = 0;/* 讀取程序結(jié)束時(shí)間 */gettimeofday(&tv_end, NULL);/* 計(jì)算一下總共所用時(shí)間 */tv_interval = icmp_tvsub(tv_end, tv_begin);return;3 . 查找數(shù)組中的標(biāo)示函數(shù)icmp_findpacket()函數(shù)icmp_findpacket()用于在數(shù)組pingpacket中查找一個(gè)報(bào)文的標(biāo)識(shí),參數(shù)為-1時(shí)表示查找一個(gè)空包,存放已經(jīng)發(fā)送成功的數(shù)據(jù)報(bào)文;其他值表示查找seq匹配的
29、標(biāo)識(shí)。/*查找一個(gè)合適的包位置當(dāng)seq為-1時(shí),表示查找空包其他值表示查找seq對(duì)應(yīng)的包*/static pingm_pakcet *icmp_findpacket(int seq)int i=0;pingm_pakcet *found = NULL;/* 查找包的位置 */if(seq = -1)/* 查找空的位置 */for(i = 0;i<128;i+)if(pingpacketi.flag = 0)found = &pingpacketi;break;else if(seq >= 0)/*查找對(duì)應(yīng)SEQ的包*/for(i = 0;i<128;i+)if(pin
30、gpacketi.seq = seq)found = &pingpacketi;break;return found;4. 統(tǒng)計(jì)數(shù)據(jù)結(jié)果函數(shù) icmp_statistics() icmp_statistics()函數(shù)用于統(tǒng)計(jì)總體的結(jié)果,包含成功發(fā)送的報(bào)文數(shù)量、成功接收的報(bào)文數(shù)量、丟失報(bào)文的百分比和總共程序運(yùn)行的時(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("
31、;- %s ping statistics -n",dest_str);/* 目的邋IP地址 */printf("%d packets transmitted, %d received, %d%c packet loss, time %d msn",packet_send,/* 發(fā)送 */packet_recv, /* 接收 */(packet_send-packet_recv)*100/packet_send, /* 丟失百分比 */'%',time); /* 時(shí)間 */主函數(shù) main()在程序中需要注意如下幾點(diǎn):Ø 使用getpro
32、tobyname()函數(shù)獲得icmp對(duì)應(yīng)的ICMP協(xié)議值。Ø 對(duì)輸入的目的主機(jī)地址兼容域名和IP地址,使用gethostbyname()函數(shù)獲得DNS對(duì)應(yīng)的IP地址,inet_addr()函數(shù)獲得字符串類型的IP地址對(duì)應(yīng)的整型值。Ø 為了防止遠(yuǎn)程主機(jī)發(fā)送過大的包或者本地來不及接收現(xiàn)象的發(fā)生,setsockopt(rawsock, 、SOL_SOCKET、SO_RCVBUF、&size、sizeof(size)函數(shù)將socket的接收緩沖區(qū)設(shè)置為128KB。Ø 對(duì)信號(hào)SIGINT進(jìn)行了截取。Ø 建立兩個(gè)線程icmp_send()和icmp_recv
33、()進(jìn)行接收和發(fā)送,然后主程序等待兩個(gè)線程結(jié)束。1主函數(shù)初始化一些必須的頭文件、函數(shù)的聲明及全局變量的聲明放在這里。#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/ti
34、me.h>#include <stdio.h>#include <string.h> /* bzero */#include <netdb.h>#include <pthread.h>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
35、);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_send(void *argv);static void icmp_sigint(int signo);static void icmp_usage();/* 保存已經(jīng)
36、發(fā)送包的狀態(tài)值 */typedef struct pingm_pakcetstruct timeval tv_begin;/*發(fā)送的時(shí)間*/struct timeval tv_end;/*接收到的時(shí)間*/short seq;/*序列號(hào)*/int flag;/*1,表示已經(jīng)發(fā)送但沒有接收到回應(yīng)包0,表示接收到回應(yīng)包*/pingm_pakcet;static pingm_pakcet pingpacket128;#define K 1024#define BUFFERSIZE 72/*發(fā)送緩沖區(qū)大小*/static unsigned char send_buffBUFFERSIZE;static
37、unsigned char recv_buff2*K;/*為防止接收溢出,接收緩沖區(qū)設(shè)置大一些*/static struct sockaddr_in dest;/*目的地址*/static int rawsock = 0;/*發(fā)送和接收線程需要的socket描述符*/static pid_t pid=0;/*進(jìn)程PID*/static int alive = 0;/*是否接收到退出信號(hào)*/static short packet_send = 0;/*已經(jīng)發(fā)送的數(shù)據(jù)包多少*/static short packet_recv = 0;/*已經(jīng)接收的數(shù)據(jù)包多少*/static char dest_s
38、tr80;/*目的主機(jī)字符串*/static struct timeval tv_begin, tv_end,tv_interval; /*本程序開始發(fā)送、結(jié)束和時(shí)間間隔*/static void icmp_usage()/* ping加IP地址或者域名 */printf("ping aaa.bbb.ccc.dddn");2. 進(jìn)行數(shù)據(jù)報(bào)文發(fā)送之前的準(zhǔn)備工作主要包含獲得目的主機(jī)的IP地址、構(gòu)建原始套接字、初始化緩沖區(qū)和變量等工作、這些工作里面還包含接收緩沖區(qū)的修改,防止返回?cái)?shù)據(jù)過大造成數(shù)據(jù)緩沖區(qū)溢出。在本段代碼里使用了 getprotobyname()函數(shù)來獲得ICMP協(xié)議
39、的類型,而不用用戶記憶協(xié)議的具體類型,只要記住名稱就可以了。/* 主程序 */int main(int argc, char *argv)struct hostent * host = NULL;/*hostent的定義如下:struct hostent char *h_name; 地址的正式名稱。char *h_aliases; 空字節(jié)-地址的預(yù)備名稱的指針。int h_addrtype; 地址類型; 通常是AF_INET。int h_length; 地址的比特長(zhǎng)度。char *h_addr_list; 零字節(jié)-主機(jī)網(wǎng)絡(luò)地址指針。網(wǎng)絡(luò)字節(jié)順序#define h_addr h_addr_lis
40、t0 h_addr_list中的第一地址。;*/struct protoent *protocol = NULL;/*取得協(xié)議編號(hào)0到4的協(xié)議數(shù)據(jù)struct protoent char *p_name; /名稱char * p_aliases; /別名short * p_proto; /編號(hào) */char protoname= "icmp"unsigned long inaddr = 1;int size = 128*K;/* 參數(shù)是否數(shù)量正確 */if(argc < 2)icmp_usage();return -1;/* 獲取協(xié)議類型ICMP */protocol
41、 = getprotobyname(protoname);if (protocol = NULL)perror("getprotobyname()");return -1;/*getprotobyname():依照通訊協(xié)定 (protocol) 的名稱來獲取該通訊協(xié)定的其他資料。 格式: struct protoent * getprotobyname( const char *name ); 參數(shù): name通訊協(xié)定名稱 傳回值: 成功 - 指向 struct protoent 的指針 */* 將目的地址字符串考出 */memcpy(dest_str, argv1, st
42、rlen(argv1)+1);memset(pingpacket, 0, sizeof(pingm_pakcet) * 128);/* socket初始化static int rawsock = 0;發(fā)送和接收線程需要的socket描述符*/ rawsock = socket(AF_INET, SOCK_RAW, protocol->p_proto);if(rawsock < 0)perror("socket");return -1;/* 為了與其他進(jìn)程的ping程序區(qū)別,加入pid */pid = getuid();/* 增大接收緩沖區(qū),防止接收的包被覆蓋 *
43、/setsockopt(rawsock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size);/*原型:extern void bzero(void *s, int n); 用法:#include <string.h> 功能:置字節(jié)字符串s的前n個(gè)字節(jié)為零且包括0*/bzero(&dest, sizeof(dest);/* 獲取目的地址的IP地址 */dest.sin_family = AF_INET;/* 獲取協(xié)議類型ICMP */protocol = getprotobyname(protoname);if (protocol
44、= NULL)perror("getprotobyname()");return -1;/*getprotobyname():依照通訊協(xié)定 (protocol) 的名稱來獲取該通訊協(xié)定的其他資料。 格式: struct protoent * getprotobyname( const char *name ); 參數(shù): name通訊協(xié)定名稱 傳回值: 成功 - 指向 struct protoent 的指針 */* 將目的地址字符串考出 */memcpy(dest_str, argv1, strlen(argv1)+1);memset(pingpacket, 0, sizeo
45、f(pingm_pakcet) * 128);/* socket初始化static int rawsock = 0;發(fā)送和接收線程需要的socket描述符*/ rawsock = socket(AF_INET, SOCK_RAW, protocol->p_proto);if(rawsock < 0)perror("socket");return -1;/* 為了與其他進(jìn)程的ping程序區(qū)別,加入pid */pid = getuid();/* 增大接收緩沖區(qū),防止接收的包被覆蓋 */setsockopt(rawsock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size);/*原型:extern void bzero(void *s, int n); 用法:#include <string.h> 功能:置字節(jié)字符串s的前n個(gè)字節(jié)為零且包括0*/bzero(&dest, sizeo
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025合同模板中央空調(diào)銷售合同范本
- 北京億歐網(wǎng)盟科技有限公司-新質(zhì)生產(chǎn)力系列:2025中國(guó)消費(fèi)級(jí)AI硬件價(jià)值洞察及GEEK50榜單報(bào)告
- 2024年三年級(jí)道德與法治下冊(cè) 第四單元 多樣的交通和通信 11四通八達(dá)的交通第二課時(shí)說課稿 新人教版
- 2024年秋七年級(jí)地理上冊(cè) 第五章 世界的發(fā)展差異 5.2《國(guó)際經(jīng)濟(jì)合作》說課稿2 (新版)湘教版
- 9 古代科技 耀我中華(說課稿)2024-2025學(xué)年統(tǒng)編版道德與法治五年級(jí)上冊(cè)
- 養(yǎng)殖設(shè)備銷售合同范例
- 2024年一年級(jí)道德與法治上冊(cè) 第16課 我有一雙明亮的眼睛說課稿 未來版
- 9 種豆子 說課稿-2023-2024學(xué)年科學(xué)二年級(jí)下冊(cè)冀人版
- 出售電廠鍋爐合同范例
- 人員轉(zhuǎn)公司合同范例
- 人教版八年級(jí)上冊(cè)地理 2024-2025學(xué)年八年級(jí)上冊(cè)地理期中測(cè)試卷(二)(含答案)
- 投標(biāo)廢標(biāo)培訓(xùn)
- 腦卒中課件完整版本
- 藥房保潔流程規(guī)范
- 電子信息工程基礎(chǔ)知識(shí)單選題100道及答案解析
- 血液透析器課件
- 吊車司機(jī)雇傭合同協(xié)議書
- 新華師大版八年級(jí)下冊(cè)初中數(shù)學(xué)全冊(cè)課時(shí)練(課后作業(yè)設(shè)計(jì))
- 致命性大出血急救專家共識(shí)
- 住院成人高血糖患者血糖監(jiān)測(cè)醫(yī)護(hù)協(xié)議處方共識(shí)
- JTS-169-2017碼頭附屬設(shè)施技術(shù)規(guī)范
評(píng)論
0/150
提交評(píng)論