《计算机网络基础课程设计Ping程序实现.docx》由会员分享,可在线阅读,更多相关《计算机网络基础课程设计Ping程序实现.docx(13页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、计算机网络基础课程设计Ping程序实现 计算机网络工程课程设计报告 题 目: Ping程序的实现 学生姓名: 学 号: 专业班级: 计科专业班 同组姓名: 指导老师: 设计时间: 2013年下学期第X周 指导老师看法: 评定成果: 签名: 日期: 年 月 日 书目 一、课程设计的目的和意义 2 二、课程设计的内容和要求 2 1.内容: 2 2.要求: 2 三、课程设计的相关技术 2 四、课程设计过程 2 1.Ping主模块 2 2.功能限制模块 4 3.数据报解析模块 5 五、课程设计小结 6 六、参考文献 7 七、附 录(程序清单) 7 八、心得体会 11 一、课程设计的目的和意义 利用IC
2、MP数据包、C语言实现Ping吩咐程序,能实现基本的Ping操作,发送ICMP回显恳求报文,用于测试个主机到只一个主机之间的连通状况。通过本程序的训练,使学生熟识ICMP报文结构,使学生对ICMP有更深的理解,驾驭Ping程序的设计方法,驾驭网络编程的方法和技巧,从而编写出功能更强大的程序。 二、课程设计的内容和要求 1.内容: 用C语言实现Ping吩咐程序,能实现基本的Ping操作,发送ICMP回显恳求报文,用于测试个主机到只一个主机之间的连通状况。2.要求: 1) 独立完成程序的设计、编码和调试。2) 系统利用C语言实现,程序调试环境为Turbo C或VC; 3) 根据课程设计规范书写课程
3、设计报告。4) 采纳VC环境进行调试运行。三、课程设计的相关技术 由于Ping程序是面对用户的应用程序,该程序运用ICMP的封装机制,通过IP协议来工作。为了实现干脆对IP和ICMP包进行操作,试验中运用RAW模式的socket编程。首先定义IP数据报首部,在IP数据报的基础上定义ICMP数据报首部,并初始化一些全局变量。接着自定义填充ICMP数据报字段函数FillICMPData()、校验和函数checksum()、解读ICMP报首部函数DecodeICMPHeader()、释放资源函Cleanup()。最终主函数通过调用这些函数来实现Ping吩咐功能。IP头与ICMP头的设置分别参照RFC
4、791及RFC792的标准,包含全部必要信息。主程序设置main()函数,主函数用库函数实现套接字编程用于数据包发送及接收,其中,数据包发送调用sendto(),数据包接收调用recvfrom( ),由于发送数据包时可能会遇到堵塞或者目标主机不通,造成超时,因此须要在发送数据包后调用一个函数推断是否超时,此处调用库函数setsockopt()来实现超时推断;其次,校验和函数采纳移位方法进行计算。套接字所须要的文件有头文件Winsocket2.h、库文件WS2_32.LIB、动态库W32_32.DLL。创建套接字的时候参数的以及在创建套接字之前必需首先运用WSAStartup函数。四、课程设计过
5、程 1.Ping主模块 Ping()函数是本程序的核心部分,它基本是调用其他模块的函数来实现最终功能,其主要布骤包括:定义及初始化各个全局变量、打开socket动态库、设置接收和发送超时值、域名地址解析、安排内存、创建及初始化ICMP报文、发送ICMP恳求报文、接收ICMP 应答报文以及解读应答报文和输出Ping结果,最终释放占用的资源其流程如下页图2.1所示。注释: (1) 该模块并非只有处理还包括推断及输出推断结果的含义; (2) 程序没运行一次就只能输出四行结果(前提是输入的地址有效),欲再次PING其他地址必需要重新启动程序。(3) 输入时不能输入目标主机名,不然ping结果为TIME
6、OUT; 起先 定义及初始化各个全局变量 推断WSAStartup函数是否调用胜利 输出调用失败 否 创建套接字以及设置socket接收超时,发送超时选项; 是 输入PING的IP地址 解析输入内容,设置PING参数 创建及填充ICMP数据报文 推断是否已发送四次 Break; 发送,接收以及解析数据包 输出PIING结果 是 结束 清除残余 否 2.功能限制模块 功能限制模块主要是为其他模块供应可调用的函数,该模块主要包括参数获得功能、计算ICMP数据报文检验和、清除SOCKET,ICMP包数据以及接受缓冲区、占用资源释放功能和显示用尸帮助功能。该模块一共包含三个函数来实现。,流程如图2.2
7、所示。Checksum起先 定义初始化cksum (size > 1) 确定cksum及size大小 是 if (size) 计算校验cksum,获得结果 cksum += *(UCHAR*)buffer; 否 结束 Cleanup起先 if (m_hSocket != INVALID_SOCKET) 关闭套接字 释放占用资源 清除ICMP包数据以及接受缓冲区 F WSACleanup(); 结束 图2.2 功能限制模块 注释: a.illICMPData是由一系列的初始化的语句在流程图中不再画出; b.Cleanup()函数中的WSACleanup(),HeapFree(),close
8、socket()都是一些库函数。checksum()校验和函数是冗余校验的一种形式。它是通过错误检测方法,对经过空间(如通信)或者时间(如计算机存储)传送的数据的完整性进行检查的一种简洁方法。3.数据报解析模块 数据报解析模块供应了解读IP选项和解读IcMP报文的功能。从本机收到目的主机返回的1cMP回显应答报文,就起先逐个地解读IcMP报文,假如须要记录路由的状况下,IcMP解析函数将调用IP选项解读函数来实现IP路由的输出(但本程序没有此功能。该模块主要由DecodeICMPHeader一个函数来实现,而中间也会调用其它模块的相应函数。其流程图如图2.3: 注释: a.推断是否为我们所要的
9、数据报回应之前,还有一些推断回应多少内容的语句未呈现出; b.函数GetTickCount()是用来记录此时我机所处的现在时间(毫秒级); DecodeICMPHeader起先 定义相关变量以及初始化; tick = GetTickCount(); 为我们所要的回应报文; 是 输出不是我们所要; tick0icmpcount=tick - icmphdr->timestamp; 推断时间是否小于1ms printf(“Reply from %s: dytes=%d time<1ms icmp_seq = %dn“,inet_ntoa(from->sin_addr), byte
10、s, icmphdr->i_seq ); printf(“Reply from %s: dytes=%d time=%d icmp_seq = %dn“,inet_ntoa(from->sin_addr), bytes,tick0icmpcount, icmphdr->i_seq); 是 是 icmpcount+; 结束 结束 否 图2.3 数据报解析模块 五、课程设计小结 1.运行操作结果:在vc里运行之后界面: 2.输入本机ip地址: 3.输入网上ip看结果: 4. 但是当网络连不通时,就会出现下图结果 六、参考文献 Visual C+网络通信编程好用案例精选(其次版)曹
11、衍龙 刘海英 编著; Windows网络编程技术 (美); 七、附 录(程序清单) #pragma comment(lib,“ws2_32.lib“) #include <winsock2.h>/创建套接字头文件 #include <ws2tcpip.h> #include <stdio.h>/标准输入输出函数 #include <stdlib.h>/好用程序库函数 #include <string.h> typedef struct iphdr unsigned int h_len:4; / 头长度 unsigned int ver
12、sion:4; / IP版本 unsigned char service; / 服务类型 unsigned short total_len; / 包的总长度 unsigned short ident; / 包标示身份 unsigned short frag_and_flags; / 标记 unsigned char ttl; / 包生命周期 unsigned char proto; / 协议类型 unsigned short checksum; / IP 校验 unsigned int sourceIP; /源IP unsigned int destIP; /目标IP IpHeader; #d
13、efine ICMP_ECHO 8 /ICMP报文类型,回显恳求 #define ICMP_ECHOREPLY 0 /ICMP报文类型,回显应答 #define ICMP_MIN 8 /最小的ICMP数据报大小 typedef struct icmphdr BYTE i_type; /ICMP报文类型 BYTE i_code; /该类型中的代码号 USHORT i_cksum; /校验和 USHORT i_id; /惟一的标识符 USHORT i_seq; /序列号 ULONG timestamp; /时间戳 IcmpHeader; #define DEF_PACKET_SIZE 32 /默认
14、数据报大小 #define MAX_PACKET 1024 / 最大的ICMP数据报大小 #define MAX_IP_HDR_SIZE 60 / 最大IP头长度 /初始化全局变量 int datasize=DEF_PACKET_SIZE; char *icmp_data=NULL; char *recvbuf=NULL; SOCKET m_hSocket= INVALID_SOCKET; char *lpdest=NULL; /填充ICMP数据报字段函数 void FillICMPData(char *icmp_data, int datasize) IcmpHeader *icmp_hdr
15、 = NULL; char*datapart = NULL; 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); /校验和函数 USHORT checksum(USHORT *b
16、uffer, 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); /解读ICMP报首部函数 void DecodeICMPHeader(char *buf, int bytes, SOCKAD
17、DR_IN *from) IpHeader*iphdr = NULL; IcmpHeader*icmphdr = NULL; unsigned short iphdrlen; DWORD tick; static int icmpcount = 0; iphdr = (IpHeader *)buf; iphdrlen = iphdr->h_len * 4; tick = GetTickCount(); if (bytes < iphdrlen + ICMP_MIN) printf(“Too few bytes from %s rn“,inet_ntoa(from->sin_a
18、ddr); icmphdr = (IcmpHeader*)(buf + iphdrlen); if (icmphdr->i_type != ICMP_ECHOREPLY) printf(“nonecho type %d received rn“, icmphdr->i_type); if (icmphdr->i_id != (USHORT)GetCurrentProcessId() printf(“其他程序的回应报文! t错误代码 %dn“, WSAGetLastError(); DWORD tick04; tick0icmpcount=tick - icmphdr->
19、timestamp; if(tick0icmpcount<1) printf(“Reply from %s: bytes=%d time<1ms icmp_seq=%dn“,inet_ntoa(from->sin_addr), bytes, icmphdr->i_seq ); else printf(“Reply from %s: bytes=%d time=%dms icmp_seq = %dn“,inet_ntoa(from->sin_addr), bytes,tick0icmpcount, icmphdr->i_seq); icmpcount+; /释
20、放资源函数 void Cleanup() if (m_hSocket != INVALID_SOCKET) closesocket(m_hSocket); HeapFree(GetProcessHeap(), 0, recvbuf); HeapFree(GetProcessHeap(), 0, icmp_data); WSACleanup(); /主函数 void main() WSADATA wsaData; char a100; printf(“ping “); scanf(“%s“,a); lpdest=a; SOCKADDR_IN m_addrDest;/结构体 SOCKADDR_IN
21、 m_addrFrom; int timeout=1000; USHORT seq_no=0; if (WSAStartup(MAKEWORD(2, 2), wsaData) != 0) printf(“Sorry, you cannot load socket dll!“); m_hSocket = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED);/创建原始套接字,该套接字用于ICMP协议 if (m_hSocket = INVALID_SOCKET) /假如套接字创建不胜利 printf(“s
22、ocket 创建失败!“); int bread = setsockopt(m_hSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)timeout, sizeof(timeout);/设置接收的超时值 if(bread = SOCKET_ERROR) printf(“设置socket接收超时选项错误!“); timeout = 1000; bread = setsockopt(m_hSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)timeout, sizeof(timeout);/设置发送的超时值 if (bread = SOCKE
23、T_ERROR) printf(“设置socket发送超时选项错误!“); memset(m_addrDest, 0, sizeof(m_addrDest);/ 用0初始化目的地地址 m_addrDest.sin_family = AF_INET;/设置地址族,这里表示运用IP地址族 if (m_addrDest.sin_addr.s_addr = inet_addr(lpdest) = INADDR_NONE)/地址转化 struct hostent *hp = NULL; if (hp = gethostbyname(lpdest) != NULL) /名字解析,依据主机名获得IP地址 m
24、emcpy(m_addrDest.sin_addr), hp->h_addr, hp->h_length);/将获得到的IP值赋给目的地地址中的相应字段 m_addrDest.sin_family = hp->h_addrtype; /将获得到的地址族值赋给目的地地址中的相应字段 else printf(“不能找到名为 %s 的主机t错误代码 %dn“,lpdest, exit(0); printf(“Pinging %s with 64 bytes of data: nn“, inet_ntoa(m_addrDest.sin_addr); datasize += sizeo
25、f(IcmpHeader); /数据报文大小须要包含ICMP报头 /依据默认堆句柄,从堆中安排MAX_PACKET内存块,新安排内存的内容将被初始化为0 icmp_data=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET); recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET); if (!icmp_data) /假如安排内存不胜利 printf(“堆安排错误!“); memset(icmp_data,0,MAX_PACKET
26、);/创建ICMP报文 FillICMPData(icmp_data,datasize); / 起先发送或接受ICMP包 int nCount=0; while(1) int bwrote; if(nCount+ = 4) break;/超过指定的记录条数则退出 (IcmpHeader*)icmp_data)->i_cksum = 0;/计算校验和前要把校验和字段设置为0 (IcmpHeader*)icmp_data)->timestamp = GetTickCount();/获得操作系统启动到现在所经过的毫秒数,设置时间戳 (IcmpHeader*)icmp_data)->
27、i_seq = seq_no+;/设置序列号 (IcmpHeader*)icmp_data)->i_cksum = checksum(USHORT*)icmp_data, datasize);/计算校验和 bwrote = sendto(m_hSocket, icmp_data, datasize, 0, (struct sockaddr*)m_addrDest, sizeof(m_addrDest);/起先发送ICMP恳求 if (bwrote = SOCKET_ERROR)/假如发送不胜利 if (WSAGetLastError() = WSAETIMEDOUT) /假如是由于超时不
28、胜利 printf(“Requrest timed out ! rn“); continue; printf(“目标不行达!t错误代码 %dn“, WSAGetLastError();/其他发送不胜利缘由 continue; if (bwrote < datasize) printf(“Wrote %d bytes rn“, bwrote); int fromlen = sizeof(m_addrFrom);/起先接收ICMP应答 bread=recvfrom(m_hSocket,recvbuf,MAX_PACKET,0,(struct sockaddr*)m_addrFrom, fro
29、mlen); if (bread = SOCKET_ERROR)/假如接收不胜利 if (WSAGetLastError() = WSAETIMEDOUT) /假如是由于超时不胜利 printf(“Requrest timed out !rn“); continue; printf(“接收数据函数调用错误!t错误代码 %dn“, WSAGetLastError();/其他接收不胜利缘由 exit(0); DecodeICMPHeader(recvbuf, bread, m_addrFrom);/解读接收到的ICMP数据报 Cleanup(); 八、心得体会 此次我们的课程设计的课题是ping程序的实现,之前我们的试验课上是在局域网中通过路由器交换机等设备由