《2022年2022年计算机网络实验报告资料 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年计算机网络实验报告资料 .pdf(14页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、课 程 设 计课程名称题目名称学生学院专业班级学号学生姓名指导教师2015 年12 月 28 日名师资料总结-精品资料欢迎下载-名师精心整理-第 1 页,共 14 页 -1 目录一、课程设计目的与意义二、课程设计的要求三、设计说明3.1、设计思路3.2、设计方案3.3、运行环境3.4、设计重点四、详细设计4.1、主程序流程图4.2、校验和函数、释放资源函数流程图4.3、ICMP 报首部函数流程图五、程序的结果与分析六、课程设计心得体会附录一:参考文献附录二:程序源代码名师资料总结-精品资料欢迎下载-名师精心整理-第 2 页,共 14 页 -2 一、课程设计的目的与意义利用 ICMP数据包、C
2、语言实现 Ping命令程序,能实现基本的Ping 操作,发送 ICMP 回显请求报文,用于测试个主机到只一个主机之间的连通情况。通过本程序的训练,熟悉ICMP报文结构,对 ICMP有更深的理解,掌握Ping 程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。二、课程设计的要求1.已知参数:目的节点IP 地址或主机名2.设计要求:通过原始套接字编程,实现Ping 的基本功能2.1 初始化 Windows Sockets网络环境;2.2 解析命令行参数,构造目的端socket地址;2.3 定义 IP、ICMP 报文;2.4 接收 ICMP 差错报文并进行解析。三、设计说明1设计
3、思路由于 Ping 程序是面向用户的应用程序,该程序使用 ICMP的封装机制,通过IP 协议来工作。为了实现直接对IP 和 ICMP包进行操作,实验中使用RAW 模式的 socket 编程。首先定义 IP 数据报首部,在 IP 数据报的基础上定义ICMP数据报首部,并初始化一些全局变量。接着自定义填充ICMP 数据报字段函数FillICMPData()、校 验 和 函 数checksum()、解 读ICMP 报 首 部 函 数DecodeICMPHeader()、释放资源函 Cleanup()。最后主函数通过调用这些函数来实现 Ping 命令功能。2.设计方案IP 头与 ICMP头的设置分别参
4、照RFC791 及 RFC792 的标准,包含所有必要信息。主程序设置main()函数,主函数用库函数实现套接字编程用于数据包发送及接收,其中,数据包发送调用sendto(),数据包接收调用recvfrom(),由于发送数据包时可能会遇到阻塞或者目标主机不通,造成超时,因此需要在发送数据包后调用一个函数判断是否超时,此处调用库函数setsockopt()来实现超时判断;其次,校验和函数采用移位方法进行计算。3.系统运行环境:VC+6.0,Window 7 操作系统平台4.设计中的重点首先遇到的问题就是套接字文件的问题。套接字所需要的文件有头文件Winsocket2.h、库文件 WS2_32.L
5、IB、动态库 W32_32.DLL。创建套接字的时候参数的以及在创建套接字之前必须首先使用WSAStartup函数、在使用完套接字之后要释放内存资源,关闭套接字这些问题都是以前未接触过的。所以在写程序的时候需要查阅大量的资料,弄懂这些问题。其次,在套接字问题解决之后,遇到的难题,也是比较重要的问题就是如何实现ICMP报文的发送和接受,以及怎样判断发送、接收超时或者找不到目的主机。最后在程序调试的时候总是出现这样或那样的错误,比如头文件错误、动态库无法导入、编辑器环境不匹配等。四、详细设计名师资料总结-精品资料欢迎下载-名师精心整理-第 3 页,共 14 页 -3 1、本程序主要是通过main(
6、)函数调用自定义函数以及其本身的一些功能,例如:打开 socket 动态库、设置接收和发送超时值、域名地址解析、分配内存、创建及初始化 ICMP报文、发送 ICMP请求报文、接收 ICMP 应答报文以及解读应答报文和输出 Ping 结果。程序流程图如下:否是是否否开始定义及初始化各个全局变量判断WSAStartup 函数是否调用成功输 出 调 用 失败创建套接字以及设置socket 接收超时,发送超时选项输入 PING 的IP 地址解析输入内容,设置PING 参数创建及填充ICMP 数据报文判断输入的ip地址没有-t 并且已发四次发送,接收以及解析数据包输出 PIING 结果Break 清除残
7、余结束名师资料总结-精品资料欢迎下载-名师精心整理-第 4 页,共 14 页 -4 2、校验和函数、释放资源函数流程图如下:是否是否是否3、ICMP报首部函数流程图如下:Checksu 开始定义初始化cksum(size 1)定 cksum 及 size大小if(size)cksum+=*(UCHAR*)buffer;计算校验cksum,获得结果结束cleanup 开始if(m_hSocket!=INVALID_SOCK关 闭 套接字释放占用资源清除ICMP包数据 以 及接 受缓冲区WSACleanup();结束名师资料总结-精品资料欢迎下载-名师精心整理-第 5 页,共 14 页 -5 De
8、codeICMPHeader 定义相关变量以及初始化tick=GetTickCount()我们所要的回应报文tick0icmpcount=tick-icmphdr-timestamp 输出不是我们所要判 断 时 间 是 否小于 1ms 结束printf(Reply from%s:dytes=%d timesin_addr)printf(Reply from%s:dytes=%d time=%d icmp_seq=%dn,inet_ntoa(from-sin_addr)icmpcount+结束名师资料总结-精品资料欢迎下载-名师精心整理-第 6 页,共 14 页 -6 五、程序的结构与分析运行结
9、果截图如下:结果分析:1、Request timed out(请求超时)名师资料总结-精品资料欢迎下载-名师精心整理-第 7 页,共 14 页 -7(1)对 方 已关 机,或 者 网络 上根 本 没 有这 个地址:比 如 在 上图 中 Ping 14.150.213.222(2)对方与自己不在同一网段内,通过路由也无法找到对方,但有时对方确实是存在的,当然不存在也是返回超时的信息。(3)对方确实存在,但设置了ICMP数据包过滤(比如防火墙设置)。2、Destination host Unreachable(目标不可达)(1)错误设置 IP 地址六、课程设计心得体会本次课程设计较好地实现了要求做
10、到的功能,但同时也遇到不少的困难和挑战。通过这次设计,不但加深了对Socket 的原始套接字编程的理解,经过实现Ping 程序,熟悉了 IP、ICMP 等,掌握 TCP/IP 网络协议的基本实现方法。也熟悉了 Window 网络编程的技术。能熟悉地使用套接字进行网络通信。熟悉了数据通信的网络技术,同时学会了跟同学合作交流完成项目的讨论方法和解决问题的能力。学会如果通过讨论、交流、找资料来独立解决所遇到的问题和不懂。更多地锻炼了独立解决问题的能力。在编写过程中,一些基本的常见的函数不会应用,这使我们小组都发现自己知识的匮乏,在以后的学习过程中得要好好的努力,多阅读一些复杂的程序,了解一个基本的函
11、数,算法和精良的编程思想,更要多动手写一些有一定难度的程序,我们不应该害怕写程序出错,应该大胆地写出自己的想法,出现错误去解决错误就能找出自己知识的漏洞和模糊点。我们还可以通过阅读别人错误的程序,试着帮别人查找错误,这样证书技能头脑中的规则还能发现一些初学者一番的错误,使自己少走弯路。附录一:参考文献【1】计算机网络谢希仁编著电子工业出版社【2】C程序设计谭浩强编著北京清华大学出版社附录二:程序源代码及部分注释#includestdafx.h#pragma comment(lib,ws2_32.lib)#include/创建套接字头文件#include#include/标准输入输出函数#inc
12、lude/实用程序库函数#include#includetypedefstructiphdr unsigned int h_len:4;/头长度unsigned int version:4;/IP版本unsigned char service;/服务类型unsigned short total_len;/包的总长度名师资料总结-精品资料欢迎下载-名师精心整理-第 8 页,共 14 页 -8 unsigned short ident;/包标示身份unsigned short frag_and_flags;/标志unsigned char ttl;/包生命周期unsigned char proto
13、;/协议类型unsigned short checksum;/IP 校验unsigned int sourceIP;/源IPunsigned int destIP;/目标IP IpHeader;#defineICMP_ECHO 8 /ICMP报文类型,回显请求#defineICMP_ECHOREPLY 0 /ICMP报文类型,回显响应应答#defineICMP_MIN 8 /最小的 ICMP 数据报大小typedefstructicmphdr BYTE i_type;/ICMP报文类型BYTE i_code;/该类型中的代码号USHORT i_cksum;/校验和USHORT i_id;/惟一
14、的标识符USHORT i_seq;/序列号ULONG timestamp;/时间戳 IcmpHeader;#defineDEF_PACKET_SIZE 32 /默认数据报大小#defineMAX_PACKET 1024 /最大的 ICMP 数据报大小#defineMAX_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 数据报字段函
15、数void FillICMPData(char *icmp_data,intdatasize)IcmpHeader*icmp_hdr=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();/GetCurrentProcessId()获取当前进程的标示符(PID)icmp_hdr-i_cksum=0;icmp_hdr-i_seq=0;datapart=icmp_d
16、ata +sizeof(IcmpHeader);名师资料总结-精品资料欢迎下载-名师精心整理-第 9 页,共 14 页 -9 /校验和函数USHORT checksum(USHORT*buffer,intsize)unsigned long cksum=0;while (size 1)cksum+=*buffer+;size -=sizeof(USHORT);if (size)cksum+=*(UCHAR*)buffer;cksum=(cksum 16)+(cksum&0 xffff);cksum+=(cksum 16);return (USHORT)(cksum);/解读ICMP 报首部函数
17、void DecodeICMPHeader(char*buf,intbytes,SOCKADDR_IN*from)IpHeader *iphdr=NULL;IcmpHeader *icmphdr=NULL;unsigned short iphdrlen;DWORD tick;staticint icmpcount=0;iphdr=(IpHeader*)buf;/从buf 中获取 IP数据包头指针 iphdrlen=iphdr-h_len*4;tick=GetTickCount();if (bytes sin_addr);icmphdr=(IcmpHeader*)(buf +iphdrlen);
18、/定位ICMP 包头起始位置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();名师资料总结-精品资料欢迎下载-名师精心整理-第 10 页,共 14 页 -10 int tick0;tick0=tick-icmphdr-timestamp;if(tick01)printf(Reply from%s:
19、bytes=%d timesin_addr),bytes,icmphdr-i_seq);elseprintf(Reply from%s:bytes=%d time=%dms icmp_seq=%dn,inet_ntoa(from-sin_addr),bytes,tick0,icmphdr-i_seq);/释放资源函数void Cleanup()if (m_hSocket!=INVALID_SOCKET)closesocket(m_hSocket);HeapFree(GetProcessHeap(),0,recvbuf);HeapFree(GetProcessHeap(),0,icmp_data
20、);WSACleanup();/主函数void main()WSADATA wsaData;char a100;printf(ping );gets(a);lpdest=a;SOCKADDR_IN m_addrDest;/结构体SOCKADDR_IN 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_
21、ICMP,NULL,0,WSA_FLAG_OVERLAPPED);/创建原始套接字,该套接字用于ICMP 协议if (m_hSocket=INVALID_SOCKET)/如果套接字创建不成功 printf(socket 创建失败!);名师资料总结-精品资料欢迎下载-名师精心整理-第 11 页,共 14 页 -11 int bread=setsockopt(m_hSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout);/设置接收的超时值if(bread=SOCKET_ERROR)printf(设置socket 接收超时选项错误!
22、);timeout=1000;bread=setsockopt(m_hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout);/设置发送的超时值if (bread=SOCKET_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(lpd
23、est)=INADDR_NONE)/地址转化 structhostent *hp=NULL;if (hp=gethostbyname(lpdest)!=NULL)/名字解析,根据主机名获取 IP地址 memcpy(&(m_addrDest.sin_addr),hp-h_addr,hp-h_length);/将获取到的 IP值赋给目的地地址中的相应字段m_addrDest.sin_family=hp-h_addrtype;/将获取到的地址族值赋给目的地地址中的相应字段 else printf(不能找到名为%s 的主机 t 错误代码%dn,lpdest,WSAGetLastError();/获取不
24、成功exit(0);printf(Pinging%s with 64 bytes of data:nn,inet_ntoa(m_addrDest.sin_addr);/inet_ntoa()将网络地址转换成“.”点隔的字符串格式 datasize+=sizeof(IcmpHeader);/数据报文大小需要包含 ICMP 报头/根据默认堆句柄,从堆中分配 MAX_PACKET内存块,新分配内存的内容将被初始化为0名师资料总结-精品资料欢迎下载-名师精心整理-第 12 页,共 14 页 -12 icmp_data=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZER
25、O_MEMORY,MAX_PACKET);recvbuf=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);if (!icmp_data)/如果分配内存不成功 printf(堆分配错误!);memset(icmp_data,0,MAX_PACKET);/将已开辟内存空间icmp_data 的首MAX_PACKET 个字节的值设为值0。FillICMPData(icmp_data,datasize);/创建ICMP 报文,/开始发送或接受 ICMP 包int nCount=0;while(1)int bwrote;if(
26、strstr(a,-t)=NULL&nCount+=4)/判断a字符数组中是否包含-t 参数并且已发 ICMP 包4次break;/超过指定的记录条数则退出 (IcmpHeader*)icmp_data)-i_cksum=0;/计算校验和前要把校验和字段设置为 0 (IcmpHeader*)icmp_data)-timestamp=GetTickCount();/获取操作系统启动到现在所经过的毫秒数,设置时间戳 (IcmpHeader*)icmp_data)-i_seq=seq_no+;/设置序列号 (IcmpHeader*)icmp_data)-i_cksum=checksum(USHORT
27、*)icmp_data,datasize);/计算校验和 bwrote=sendto(m_hSocket,icmp_data,datasize,0,(structsockaddr*)&m_addrDest,sizeof(m_addrDest);/开始发送 ICMP 请求if (bwrote=SOCKET_ERROR)/如果发送不成功 if (WSAGetLastError()=WSAETIMEDOUT)/如果是由于超时不成功 printf(Requrest timed out!rn);continue;printf(目标不可达!t 错误代码%dn,WSAGetLastError();/其他发送
28、不成功原因continue;if (bwrote datasize)名师资料总结-精品资料欢迎下载-名师精心整理-第 13 页,共 14 页 -13 printf(Wrote%d bytes rn,bwrote);int fromlen=sizeof(m_addrFrom);/开始接收 ICMP 应答 bread=recvfrom(m_hSocket,recvbuf,MAX_PACKET,0,(structsockaddr*)&m_addrFrom,&fromlen);/recvfrom()用来接收远程主机经指定的socket 传来的数据,并把数据传到由参数 recvbuf 指向的内存空间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 数据报 Sleep(800);Cleanup();名师资料总结-精品资料欢迎下载-名师精心整理-第 14 页,共 14 页 -