计算机网络实验报告资料.docx

上传人:b****8 文档编号:11465188 上传时间:2023-03-01 格式:DOCX 页数:18 大小:213.40KB
下载 相关 举报
计算机网络实验报告资料.docx_第1页
第1页 / 共18页
计算机网络实验报告资料.docx_第2页
第2页 / 共18页
计算机网络实验报告资料.docx_第3页
第3页 / 共18页
计算机网络实验报告资料.docx_第4页
第4页 / 共18页
计算机网络实验报告资料.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

计算机网络实验报告资料.docx

《计算机网络实验报告资料.docx》由会员分享,可在线阅读,更多相关《计算机网络实验报告资料.docx(18页珍藏版)》请在冰豆网上搜索。

计算机网络实验报告资料.docx

计算机网络实验报告资料

课程设计

课程名称

题目名称

学生学院

专业班级

学号

学生姓名

指导教师

 

2015年12月28日

 

一、课程设计目的与意义

二、课程设计的要求

三、设计说明

3.1、设计思路

3.2、设计方案

3.3、运行环境

3.4、设计重点

四、详细设计

4.1、主程序流程图

4.2、校验和函数、释放资源函数流程图

4.3、ICMP报首部函数流程图

五、程序的结果与分析

六、课程设计心得体会

附录一:

参考文献

附录二:

程序源代码

 

一、课程设计的目的与意义

利用ICMP数据包、C语言实现Ping命令程序,能实现基本的Ping操作,发送ICMP回显请求报文,用于测试—个主机到只一个主机之间的连通情况。

通过本程序的训练,熟悉ICMP报文结构,对ICMP有更深的理解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。

二、课程设计的要求

1.已知参数:

目的节点IP地址或主机名

2.设计要求:

通过原始套接字编程,实现Ping的基本功能

2.1初始化WindowsSockets网络环境;

2.2解析命令行参数,构造目的端socket地址;

2.3定义IP、ICMP报文;

2.4接收ICMP差错报文并进行解析。

三、设计说明

1.设计思路

由于Ping程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。

为了实现直接对IP和ICMP包进行操作,实验中使用RAW模式的socket编程。

首先定义IP数据报首部,在IP数据报的基础上定义ICMP数据报首部,并初始化一些全局变量。

接着自定义填充ICMP数据报字段函数FillICMPData()、校验和函数checksum()、解读ICMP报首部函数DecodeICMPHeader()、释放资源函Cleanup()。

最后主函数通过调用这些函数来实现Ping命令功能。

2.设计方案

IP头与ICMP头的设置分别参照RFC791及RFC792的标准,包含所有必要信息。

主程序设置main()函数,主函数用库函数实现套接字编程用于数据包发送及接收,其中,数据包发送调用sendto(),数据包接收调用recvfrom(),由于发送数据包时可能会遇到阻塞或者目标主机不通,造成超时,因此需要在发送数据包后调用一个函数判断是否超时,此处调用库函数setsockopt()来实现超时判断;其次,校验和函数采用移位方法进行计算。

3.系统运行环境:

VC++6.0,Window7操作系统平台

4.设计中的重点

首先遇到的问题就是套接字文件的问题。

套接字所需要的文件有头文件Winsocket2.h、库文件WS2_32.LIB、动态库W32_32.DLL。

创建套接字的时候参数的以及在创建套接字之前必须首先使用WSAStartup函数、在使用完套接字之后要释放内存资源,关闭套接字这些问题都是以前未接触过的。

所以在写程序的时候需要查阅大量的资料,弄懂这些问题。

其次,在套接字问题解决之后,遇到的难题,也是比较重要的问题就是如何实现ICMP报文的发送和接受,以及怎样判断发送、接收超时或者找不到目的主机。

最后在程序调试的时候总是出现这样或那样的错误,比如头文件错误、动态库无法导入、编辑器环境不匹配等。

四、详细设计

1、本程序主要是通过main()函数调用自定义函数以及其本身的一些功能,例如:

打开socket动态库、设置接收和发送超时值、域名地址解析、分配内存、创建及初始化ICMP报文、发送ICMP请求报文、接收ICMP应答报文以及解读应答报文和输出Ping结果。

程序流程图如下:

 

 

 

 

2、校验和函数、释放资源函数流程图如下:

 

 

否是否

 

 

 

3、ICMP报首部函数流程图如下:

 

 

五、程序的结构与分析

运行结果截图如下:

结果分析:

1、Requesttimedout(请求超时)

(1)对方已关机,或者网络上根本没有这个地址:

比如在上图中Ping14.150.213.222

(2)对方与自己不在同一网段内,通过路由也无法找到对方,但有时对方确实是存在的,当然不存在也是返回超时的信息。

(3)对方确实存在,但设置了ICMP数据包过滤(比如防火墙设置)。

2、DestinationhostUnreachable(目标不可达)

(1)错误设置IP地址

六、课程设计心得体会

本次课程设计较好地实现了要求做到的功能,但同时也遇到不少的困难和挑战。

通过这次设计,不但加深了对Socket的原始套接字编程的理解,经过实现Ping程序,熟悉了IP、ICMP等,掌握TCP/IP网络协议的基本实现方法。

也熟悉了Window网络编程的技术。

能熟悉地使用套接字进行网络通信。

熟悉了数据通信的网络技术,同时学会了跟同学合作交流完成项目的讨论方法和解决问题的能力。

学会如果通过讨论、交流、找资料来独立解决所遇到的问题和不懂。

更多地锻炼了独立解决问题的能力。

在编写过程中,一些基本的常见的函数不会应用,这使我们小组都发现自己知识的匮乏,在以后的学习过程中得要好好的努力,多阅读一些复杂的程序,了解一个基本的函数,算法和精良的编程思想,更要多动手写一些有一定难度的程序,我们不应该害怕写程序出错,应该大胆地写出自己的想法,出现错误去解决错误就能找出自己知识的漏洞和模糊点。

我们还可以通过阅读别人错误的程序,试着帮别人查找错误,这样证书技能头脑中的规则还能发现一些初学者一番的错误,使自己少走弯路。

附录一:

参考文献

【1】计算机网络谢希仁编著电子工业出版社

【2】C程序设计谭浩强编著北京清华大学出版社

附录二:

程序源代码及部分注释

#include"stdafx.h"

#pragmacomment(lib,"ws2_32.lib")

#include//创建套接字头文件

#include

#include//标准输入输出函数

#include//实用程序库函数

#include

#include

typedefstructiphdr

{

unsignedinth_len:

4;//头长度

unsignedintversion:

4;//IP版本

unsignedcharservice;//服务类型

unsignedshorttotal_len;//包的总长度

unsignedshortident;//包标示身份

unsignedshortfrag_and_flags;//标志

unsignedcharttl;//包生命周期

unsignedcharproto;//协议类型

unsignedshortchecksum;//IP校验

unsignedintsourceIP;//源IP

unsignedintdestIP;//目标IP

}IpHeader;

#defineICMP_ECHO8//ICMP报文类型,回显请求

#defineICMP_ECHOREPLY0//ICMP报文类型,回显响应应答

#defineICMP_MIN8//最小的ICMP数据报大小

typedefstructicmphdr

{

BYTEi_type;//ICMP报文类型

BYTEi_code;//该类型中的代码号

USHORTi_cksum;//校验和

USHORTi_id;//惟一的标识符

USHORTi_seq;//序列号

ULONGtimestamp;//时间戳

}IcmpHeader;

#defineDEF_PACKET_SIZE32//默认数据报大小

#defineMAX_PACKET1024//最大的ICMP数据报大小

#defineMAX_IP_HDR_SIZE60//最大IP头长度

//初始化全局变量

intdatasize=DEF_PACKET_SIZE;

char*icmp_data=NULL;

char*recvbuf=NULL;

SOCKETm_hSocket=INVALID_SOCKET;

char*lpdest=NULL;

//填充ICMP数据报字段函数

voidFillICMPData(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_data+sizeof(IcmpHeader);

}

//校验和函数

USHORTchecksum(USHORT*buffer,intsize)

{

unsignedlongcksum=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报首部函数

voidDecodeICMPHeader(char*buf,intbytes,SOCKADDR_IN*from)

{

IpHeader*iphdr=NULL;

IcmpHeader*icmphdr=NULL;

unsignedshortiphdrlen;

DWORDtick;

staticinticmpcount=0;

iphdr=(IpHeader*)buf;//从buf中获取IP数据包头指针

iphdrlen=iphdr->h_len*4;

tick=GetTickCount();

if(bytes

{

printf("Toofewbytesfrom%s\r\n",inet_ntoa(from->sin_addr));

}

icmphdr=(IcmpHeader*)(buf+iphdrlen);//定位ICMP包头起始位置

if(icmphdr->i_type!

=ICMP_ECHOREPLY)

{

printf("nonechotype%dreceived\r\n",icmphdr->i_type);

}

if(icmphdr->i_id!

=(USHORT)GetCurrentProcessId())

{

printf("其他程序的回应报文!

\t错误代码%d\n",WSAGetLastError());

}

inttick0;

tick0=tick-icmphdr->timestamp;

if(tick0<1)

printf("Replyfrom%s:

bytes=%dtime<1msicmp_seq=%d\n",inet_ntoa(from->sin_addr),bytes,icmphdr->i_seq);

else

printf("Replyfrom%s:

bytes=%dtime=%dmsicmp_seq=%d\n",inet_ntoa(from->sin_addr),bytes,tick0,icmphdr->i_seq);

}

//释放资源函数

voidCleanup()

{

if(m_hSocket!

=INVALID_SOCKET)

closesocket(m_hSocket);

HeapFree(GetProcessHeap(),0,recvbuf);

HeapFree(GetProcessHeap(),0,icmp_data);

WSACleanup();

}

 

//主函数

voidmain()

{

WSADATAwsaData;

chara[100];

printf("ping");

gets(a);

lpdest=a;

SOCKADDR_INm_addrDest;//结构体

SOCKADDR_INm_addrFrom;

inttimeout=1000;

USHORTseq_no=0;

if(WSAStartup(MAKEWORD(2,2),&wsaData)!

=0)

{

printf("Sorry,youcannotloadsocketdll!

");

}

m_hSocket=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);//创建原始套接字,该套接字用于ICMP协议

if(m_hSocket==INVALID_SOCKET)//如果套接字创建不成功

{

printf("socket创建失败!

");

}

intbread=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==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(lpdest))==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错误代码%d\n",lpdest,WSAGetLastError());//获取不成功

exit(0);

}

}

printf("Pinging%swith64bytesofdata:

\n\n",inet_ntoa(m_addrDest.sin_addr));//inet_ntoa()将网络地址转换成“.”点隔的字符串格式

datasize+=sizeof(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);//将已开辟内存空间 icmp_data 的首 MAX_PACKET 个字节的值设为值 0。

FillICMPData(icmp_data,datasize);//创建ICMP报文,

//开始发送或接受ICMP包

intnCount=0;

while

(1)

{

intbwrote;

if(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*)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("Requresttimedout!

\r\n");

continue;

}

printf("目标不可达!

\t错误代码%d\n",WSAGetLastError());//其他发送不成功原因

continue;

}

if(bwrote

{

printf("Wrote%dbytes\r\n",bwrote);

}

intfromlen=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("Requresttimedout!

\r\n");

continue;

}

printf("接收数据函数调用错误!

\t错误代码%d\n",WSAGetLastError());//其他接收不成功原因

exit(0);

}

DecodeICMPHeader(recvbuf,bread,&m_addrFrom);//解读接收到的ICMP数据报

Sleep(800);

}

Cleanup();

}

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 学科竞赛

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1