计算机网络课程设计之Tracert与Ping程序设计与实现
前言
本實驗主要是應用ICMP報文實現Tracert和Ping功能,主要用的是Windows中的庫,所以程序只能在Windows下運行。
在博客結束的地方,附上C/C++的Tracert源碼和Ping源碼,兩個源碼來自指導書和網絡。
我的程序也改編自這兩個源碼
白嫖容易,創作不易,本文原創,轉載請注明!!!
源碼和可運行程序:
鏈接:https://pan.baidu.com/s/1A9KctmpP2JJgyW2wLrehIg
提取碼:Lin2
計算機網絡課程設計:
計算機網絡課程設計之網絡聊天程序的設計與實現
計算機網絡課程設計之Tracert與Ping程序設計與實現
計算機網絡課程設計之基于 IP 多播的網絡會議程序
計算機網絡課程設計之網絡嗅探器的設計與實現
計算機網絡課程設計之電子郵件客戶端程序設計與實現
計算機網絡課程設計之TELNET 終端設計與實現
計算機網絡課程設計之網絡代理服務器的設計與實現
計算機網絡課程設計之簡單 Web Server 程序的設計與實現
Qt入門系列:
Qt學習之C++基礎
Qt學習之Qt安裝
Qt學習之Qt基礎入門(上)
Qt學習之Qt基礎入門(中)
Qt學習之Qt基礎入門(下)
創作不易,整個課程設計程序3000多行代碼,所有實驗都寫在了一個程序中,時間有限,能力不足,轉載望注明!!!
本文鏈接
個人博客:https://ronglin.fun/archives/266
PDF鏈接:見博客網站
CSDN: https://blog.csdn.net/RongLin02/article/details/122510039
實驗題目
Tracert 與 Ping 程序設計與實現
實驗目的
了解 Tracert 程序的實現原理
了解 Ping 程序的實現原理
參照附錄,了解 Tracert 程序的實現原理,并調試通過。然后參考 Tracert 程序和教材 4.4.2 節,編寫一個 Ping 程序,并能測試本局域網的所有機器是否在線,例如 QuickPing 程序。
總體設計
(含背景知識或基本原理與算法、或模塊介紹、設計步驟等)
先簡單的說一下原理,就是不論是Tracert還是Ping,都是利用了IPPROTO_ICMP類型的數據報,格式如下:
然后通過修改其中的部分數據來實現對應的功能
Tracert
Tracert的主要功能就是獲取數據報所經過的路由器線路
Tracert的基本原理如下,構造一個數據報,將它的初始TTL值設置為1,這樣的話,主機將數據發出到第一個路由器1號,然后這個路由器1號將TTL-1,TTL=0,然后路由器1號就把數據報丟棄了,然后向源主機發送一個ICMP時間超過差錯報告報文。然后主機就通過解析回傳的數據就知道了路由器1號的信息。然后再構造一個數據報,,將它的TTL值設置為2,這樣數據就如此流向,主機->路由器1號->路由器2號,然后路由器2號把數據丟棄,發送差錯報告,主機就是知道了路由器2號的信息。如此往復直到數據到達了目的主機。
在我的程序設計中,用一個單獨的線程完成Tracert功能,同時在線程中的run()方法中構造套接字,創建連接,得到結果,分析結果,直到到達目的地址。用單獨的線程主要是因為在反復發送接收數據時需要較長的時間。
同時根據指導書上的Tracert源代碼構造以下方法
同時還有若干槽函數和setter getter方法就不貼出來了
Ping
ping的原理也是利用ICMP數據報文,主要就是檢測連通性
PING的源碼我是從網上找的MSDN的源碼,思路如下:
初始化WSADATA ->構造ICMP數據報->創建原始套接字 ->設置發送/接受超時時間 -> 用sendto發送ICMP報文->用recvfrom接受返回的數據 -> 分析數據 ->將結果返回給前端界面
主要設計的方法如下:
//填充ICMP數據報void fill_icmp_data(char *, int);//計算校驗和USHORT checksum(USHORT *, int);//解析返回的數據報bool decode_resp(char *,int,struct sockaddr_in *);詳細設計
(含主要的數據結構、程序流程圖、關鍵代碼等)
Tracert
界面上圖左側
這個主要是要用到3個參數,第一個是要Tracert的IP地址和域名,第二個是要設置的超時時間,第三個是設置轉發的節點
IP地址和域名
這個是根據用戶輸入,然后用Windows API提供的方法解析ip和域名,部分代碼如下:
bool MyTracert::isLegalIP(QString ip) {WSADATA* wsa =(WSADATA*) malloc(sizeof(WSADATA));WSAStartup(MAKEWORD(2,2),wsa);bool flag = true;//得到 IP 地址u_long ulDestIP=inet_addr(ip.toUtf8().data());//轉換不成功時按域名解析if(ulDestIP==INADDR_NONE){hostent * pHostent=gethostbyname(ip.toUtf8().data());if(!pHostent){flag = false;}}free(wsa);return flag; }通過此方法就知道了用戶輸入的ip是否合法
超時時間
超時時間主要是用在創建套接字的時候,在Windows API中用法如下,其中變量iTimeout(:int)就是設置超時時間
//接收超時 (用于任意類型、任意狀態套接口的設置選項值)setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout));//發送超時setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout));當接收時間/發送時間超過設定的值的時候,就會出現錯誤WSAGetLastError()==WSAETIMEDOUT
轉發節點個數
這個比較簡單了,就是設置最大跳站數,就是最多允許查看的轉發的路由器的節點數量
int DEF_MAX_HOP=30; //最大跳站數然后點擊開始就啟動線程,然后將結果通過槽函數返回給前端界面
Ping
界面上圖右側
這個主要是要用到4個參數,第一個是IP地址的開始值,第二個是IP地址結束值,第三個是設置超時時間,第四個設置ping的次數
IP范圍
范圍就是從開始到結束,同時只允許用戶修改點分十進制的最后一部分,同時需要在前端界面中判斷用戶輸入的是否正確,就是開始值<=結束值,同時根據用戶輸入的范圍,構造出來一個IPList,然后傳到MyPing類中。
超時時間
原理同Tracert
ping次數
這個就是對同一個ip地址發送ICMP數據報的次數,發送一次解析一次,如果解析成功(Ping通),返回結果,如果解析失敗(無數據/超時/無法解析),則再次發送數據報。
同時以上也寫在了一個子線程中,以防長時間導致前端界面無響應。
實驗結果與分析
結果如下:
同時啟動兩個功能
左側開始輸出結果,因為超時時間問題,返回的結果都是超時
右側根據輸入開始ping每一個結果然后輸出結果
運行結果如上
左側經過17跳之后成功的到達,并且顯示的域名對應的ip地址
右側從IP:39.101.201.10 到IP:39.101.201.30然后分別輸出結果
通過用cmd的Tracert指令和Ping指令檢驗,結果正確
小結與心得體會
對ICMP有了更深入的理解,同時常用的ping功能也知道了它的實現原理,獲益匪淺,對計算機網絡中網絡層有了更深入的認識。
=w=
附
Tracert源碼
#include <iostream> #include <winsock2.h> #include <ws2tcpip.h> using namespace std; #pragma comment(lib, "Ws2_32.lib") //IP 報頭 typedef struct {unsigned char hdr_len:4; //4 位頭部長度unsigned char version:4; //4 位版本號unsigned char tos; //8 位服務類型unsigned short total_len; //16 位總長度unsigned short identifier; //16 位標識符unsigned short frag_and_flags; //3 位標志加 13 位片偏移unsigned char ttl; //8 位生存時間unsigned char protocol; //8 位上層協議號unsigned short checksum; //16 位校驗和unsigned long sourceIP; //32 位源 IP 地址unsigned long destIP; //32 位目的 IP 地址 } IP_HEADER; //ICMP 報頭 typedef struct {BYTE type; //8 位類型字段BYTE code; //8 位代碼字段USHORT cksum; //16 位校驗和USHORT id; //16 位標識符USHORT seq; //16 位序列號 } ICMP_HEADER; //報文解碼結構 typedef struct {USHORT usSeqNo; //序列號DWORD dwRoundTripTime; //往返時間in_addr dwIPaddr; //返回報文的 IP 地址 } DECODE_RESULT; //計算網際校驗和函數 USHORT checksum(USHORT *pBuf,int iSize) {unsigned long cksum=0;while(iSize>1){cksum+=*pBuf++;iSize-=sizeof(USHORT);}if(iSize){cksum+=*(UCHAR *)pBuf;}cksum=(cksum>>16)+(cksum&0xffff);cksum+=(cksum>>16);return (USHORT)(~cksum); } //對數據包進行解碼 BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) { //檢查數據報大小的合法性IP_HEADER* pIpHdr = (IP_HEADER*)pBuf;int iIpHdrLen = pIpHdr->hdr_len * 4;if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER)))return FALSE; //根據 ICMP 報文類型提取 ID 字段和序列號字段ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iIpHdrLen);USHORT usID,usSquNo;if(pIcmpHdr->type==ICMP_ECHO_REPLY) //ICMP 回顯應答報文{usID=pIcmpHdr->id; //報文 IDusSquNo=pIcmpHdr->seq; //報文序列號}else if(pIcmpHdr->type==ICMP_TIMEOUT)//ICMP 超時差錯報文{char * pInnerIpHdr=pBuf+iIpHdrLen+sizeof(ICMP_HEADER); //載荷中的 IP 頭int iInnerIPHdrLen=((IP_HEADER *)pInnerIpHdr)->hdr_len*4; //載荷中的 IP 頭長ICMP_HEADER * pInnerIcmpHdr=(ICMP_HEADER *)(pInnerIpHdr+iInnerIPHdrLen);//載荷中的 ICMP 頭usID=pInnerIcmpHdr->id; //報文 IDusSquNo=pInnerIcmpHdr->seq; //序列號}else{return false;} //檢查 ID 和序列號以確定收到期待數據報if(usID!=(USHORT)GetCurrentProcessId()||usSquNo!=DecodeResult.usSeqNo){return false;} //記錄 IP 地址并計算往返時間DecodeResult.dwIPaddr.s_addr=pIpHdr->sourceIP;DecodeResult.dwRoundTripTime=GetTickCount()-DecodeResult.dwRoundTripTime; //處理正確收到的 ICMP 數據報if (pIcmpHdr->type == ICMP_ECHO_REPLY ||pIcmpHdr->type == ICMP_TIMEOUT){ //輸出往返時間信息if(DecodeResult.dwRoundTripTime)cout<<" "<<DecodeResult.dwRoundTripTime<<"ms"<<flush;elsecout<<" "<<"<1ms"<<flush;}return true; } int main() { //初始化 Windows sockets 網絡環境WSADATA wsa;WSAStartup(MAKEWORD(2,2),&wsa);char IpAddress[255];cout<<"請輸入一個 IP 地址或域名:";cin>>IpAddress; //得到 IP 地址u_long ulDestIP=inet_addr(IpAddress); //轉換不成功時按域名解析if(ulDestIP==INADDR_NONE){hostent * pHostent=gethostbyname(IpAddress);if(pHostent){ulDestIP=(*(in_addr*)pHostent->h_addr).s_addr;}else{cout<<"輸入的 IP 地址或域名無效!"<<endl;WSACleanup();return 0;}}cout<<"Tracing route to "<<IpAddress<<" with a maximum of 30 hops.\n"<<endl; //填充目地端 socket 地址sockaddr_in destSockAddr;ZeroMemory(&destSockAddr,sizeof(sockaddr_in));destSockAddr.sin_family=AF_INET; //地址族 使用 IPv4 進行通信destSockAddr.sin_addr.s_addr=ulDestIP; // 32位的IP地址 //創建原始套接字 詳細說明:https://www.cnblogs.com/hgwang/p/6118634.htmlSOCKET sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED); //SOCK_RAW表示原始套接字,即不是TCP也不是UDP //超時時間int iTimeout=3000; //接收超時 (用于任意類型、任意狀態套接口的設置選項值)setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout)); //發送超時setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout)); //構造 ICMP 回顯請求消息,并以 TTL 遞增的順序發送報文 //ICMP 類型字段const BYTE ICMP_ECHO_REQUEST=8; //請求回顯const BYTE ICMP_ECHO_REPLY=0; //回顯應答const BYTE ICMP_TIMEOUT=11; //傳輸超時 //其他常量定義const int DEF_ICMP_DATA_SIZE=32; //ICMP 報文默認數據字段長度const int MAX_ICMP_PACKET_SIZE=1024;//ICMP 報文最大長度(包括報頭)const DWORD DEF_ICMP_TIMEOUT=3000; //回顯應答超時時間const int DEF_MAX_HOP=30; //最大跳站數 //填充 ICMP 報文中每次發送時不變的字段char IcmpSendBuf[sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE];//發送緩沖區memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); //初始化發送緩沖區char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE]; //接收緩沖區memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); //初始化接收緩沖區ICMP_HEADER * pIcmpHeader=(ICMP_HEADER*)IcmpSendBuf;pIcmpHeader->type=ICMP_ECHO_REQUEST; //類型為請求回顯pIcmpHeader->code=0; //代碼字段為 0pIcmpHeader->id=(USHORT)GetCurrentProcessId(); //ID 字段為當前進程號memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE);//數據字段USHORT usSeqNo=0; //ICMP 報文序列號int iTTL=1; //TTL 初始值為 1BOOL bReachDestHost=FALSE; //循環退出標志int iMaxHot=DEF_MAX_HOP; //循環的最大次數DECODE_RESULT DecodeResult; //傳遞給報文解碼函數的結構化參數while(!bReachDestHost&&iMaxHot--){ //設置 IP 報頭的 TTL 字段setsockopt(sockRaw,IPPROTO_IP,IP_TTL,(char *)&iTTL,sizeof(iTTL));cout<<iTTL<<flush; //輸出當前序號 //填充 ICMP 報文中每次發送變化的字段((ICMP_HEADER *)IcmpSendBuf)->cksum=0; //校驗和先置為 0((ICMP_HEADER *)IcmpSendBuf)->seq=htons(usSeqNo++); //填充序列號((ICMP_HEADER *)IcmpSendBuf)->cksum=checksum((USHORT *)IcmpSendBuf,sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE); //計算校驗和 //記錄序列號和當前時間DecodeResult.usSeqNo=((ICMP_HEADER*)IcmpSendBuf)->seq; //當前序號DecodeResult.dwRoundTripTime=GetTickCount(); //當前時間 //發送 TCP 回顯請求信息sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(sockaddr*)&destSockAddr,sizeof(destSockAddr)); //接收 ICMP 差錯報文并進行解析處理sockaddr_in from; //對端 socket 地址int iFromLen=sizeof(from); //地址結構大小int iReadDataLen; //接收數據長度while(1){ //接收數據iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(sockaddr*)&from,&iFromLen);if(iReadDataLen!=SOCKET_ERROR)//有數據到達{ //對數據包進行解碼if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen,DecodeResult,ICMP_ECHO_REPLY,ICMP_TIMEOUT)){ //到達目的地,退出循環if(DecodeResult.dwIPaddr.s_addr==destSockAddr.sin_addr.s_addr)bReachDestHost=true; //輸出 IP 地址cout<<'\t'<<inet_ntoa(DecodeResult.dwIPaddr)<<endl;break;}}else if(WSAGetLastError()==WSAETIMEDOUT) //接收超時,輸出*號{cout<<" *"<<'\t'<<"Request timed out."<<endl;break;}else{break;}}iTTL++; //遞增 TTL 值}return 0; }Ping源碼
/******************************************************************************\ * ping.c - Simple ping utility using SOCK_RAW * * This is a part of the Microsoft Source Code Samples. * Copyright 1996-1997 Microsoft Corporation. * All rights reserved. * This source code is only intended as a supplement to * Microsoft Development Tools and/or WinHelp documentation. * See these sources for detailed information regarding the * Microsoft samples programs. \******************************************************************************/#define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #pragma comment(lib,"ws2_32.lib")#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 headerunsigned int version:4; // Version of IPunsigned char tos; // Type of serviceunsigned short total_len; // total length of the packetunsigned short ident; // unique identifierunsigned short frag_and_flags; // flagsunsigned char ttl;unsigned char proto; // protocol (TCP, UDP etc)unsigned short checksum; // IP checksumunsigned int sourceIP;unsigned int destIP; } IpHeader;// // ICMP header // typedef struct _ihdr {BYTE i_type; //消息類型BYTE i_code; //代碼 /* type sub code */USHORT i_cksum; //校驗和USHORT i_id; //ID號USHORT i_seq; //序列號ULONG timestamp; //時間戳 /* This is not the std header, but we reserve space for time */ } IcmpHeader; //ICMP報文 包括報頭和數據#define STATUS_FAILED 0xFFFF #define DEF_PACKET_SIZE 32 #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); void decode_resp(char *,int,struct sockaddr_in *);int main(int argc, char **argv) {WSADATA wsaData;SOCKET sockRaw;struct sockaddr_in dest;struct hostent * hp;int bread,datasize;int timeout = 1000;char *dest_ip;char *icmp_data;char *recvbuf;unsigned int addr=0;USHORT seq_no = 0;struct sockaddr_in from;int fromlen = sizeof(from);if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());ExitProcess(STATUS_FAILED);}/*為了使用發送接收超時設置(即設置SO_RCVTIMEO, SO_SNDTIMEO),// 必須將標志位設為WSA_FLAG_OVERLAPPED !*/sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED); //建立一個原始套接字//sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0);if (sockRaw == INVALID_SOCKET){fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());ExitProcess(STATUS_FAILED);}timeout = 1000; //設置接收超時時間bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); //RECVTIMEO是接收超時時間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)); //SNDTIMEO是發送超時時間if(bread == SOCKET_ERROR){fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());ExitProcess(STATUS_FAILED);}memset(&dest,0,sizeof(dest)); //目標地址清零hp = gethostbyname("www.baidu.com"); //通過域名或者主機名獲取IP地址if (!hp) //失敗返回NULL{ExitProcess(STATUS_FAILED);}else{addr = inet_addr("14.215.177.37"); //www.baidu.com的ip地址}if ((!hp) && (addr == INADDR_NONE)) //既不是域名也不是點分十進制的IP地址{ExitProcess(STATUS_FAILED);}if (hp != NULL) //獲取的是域名memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); //從hostent得到的對方ip地址elsedest.sin_addr.s_addr = addr;if (hp)dest.sin_family = hp->h_addrtype; //sin_family不是一定只能填AF_INET嗎?elsedest.sin_family = AF_INET;addr = inet_addr("39.101.201.13");dest.sin_addr.s_addr = addr;//addr = inet_addr("14.215.177.37");dest_ip = inet_ntoa(dest.sin_addr); //目標IP地址datasize = DEF_PACKET_SIZE; //ICMP包數據大小設定為32datasize += sizeof(IcmpHeader); //另外加上ICMP包的包頭 其實包頭占12個字節icmp_data = (char *)xmalloc(MAX_PACKET);//發送icmp_data數據包內存recvbuf = (char *)xmalloc(MAX_PACKET); //存放接收到的數據if (!icmp_data) //分配內存{ExitProcess(STATUS_FAILED);}memset(icmp_data,0,MAX_PACKET);fill_icmp_data(icmp_data,datasize); //只填充了ICMP包fprintf(stdout,"\nPinging %s ....\n\n",dest_ip);while(1){int bwrote;((IcmpHeader*)icmp_data)->i_cksum = 0;((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); //時間戳((IcmpHeader*)icmp_data)->i_seq = seq_no++; //ICMP的序列號((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize); //icmp校驗位//下面這個函數的問題是 發送數據只是ICMP數據包,而接收到的數據時包含ip頭的 也就是發送和接收不對等//問題是sockRaw 設定了協議為 IPPROTO_ICMPbwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest, sizeof(dest));if (bwrote == SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT) //發送時間超時{printf("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("timed out\n");continue;}fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());ExitProcess(STATUS_FAILED);}decode_resp(recvbuf,bread,&from);Sleep(1000);}WSACleanup();system("pause");return 0; }/* The response is an IP packet. We must decode the IP header to locate the ICMP data */ void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {IpHeader *iphdr;IcmpHeader *icmphdr;unsigned short iphdrlen;iphdr = (IpHeader *)buf; //接收到的數據就是原始的IP數據報iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytesif (bytes < iphdrlen + ICMP_MIN){printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));}icmphdr = (IcmpHeader*)(buf + iphdrlen);if(icmphdr->i_type == 3){printf("network unreachable -- Response from %s.\n",inet_ntoa(from->sin_addr));return ;}if (icmphdr->i_id != (USHORT)GetCurrentProcessId()){fprintf(stderr,"someone else's packet!\n");return ;}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(" ttl: %d",iphdr->ttl);printf("\n"); }//完成ICMP的校驗 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_ECHO要求收到包的主機回復此ICMP包icmp_hdr->i_code = 0;icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); //id填當前進程的idicmp_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)); //填充了一些廢物 }總結
以上是生活随笔為你收集整理的计算机网络课程设计之Tracert与Ping程序设计与实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++学习之Dev-C++安装与调试
- 下一篇: java 读取1m文件_java的Fil