题目8Ping程序的实现报告文档格式.docx
《题目8Ping程序的实现报告文档格式.docx》由会员分享,可在线阅读,更多相关《题目8Ping程序的实现报告文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
4.1系统设计3
4.2系统实现4
5、设计总结13
5.1完成的工作及评价13
5.2遇到的问题及解决过程13
5.3心得体会及建议14
6、使用说明14
参考文献14
1、课程设计任务描述
另写一个程序,取代windows下的Ping程序命令,可以Ping指定主机、一批主机,并显示输出结果。
2、设计原理及相关知识
2.1设计原理
ping命令的工作原理[1]是:
向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者,通过返回的信息来判断网络的连接状况。
要实现直接对IP和ICMP包进行操作,设计采用RAW模式的SOCKET编程,实现网络的连通性测试,探测主机到主机之间是否可以通信,如果不能ping到某台主机,表明不能和这台主机建立连接。
Ping程序是面向向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。
2.2相关知识
了解ping命令实现原理[2],就要了解ping命令所使用到的TCP/IP协议。
PING利用ICMP协议包来测试另一个主机是否可达。
原理是用类型码为0的ICMP发送请求,收到请求主机则用类型码为8的ICMP回应。
Ping程序来计算时间间隔,并计算有多少个包被送达。
用户就可以判断网络的大致情况。
ICMP协议是IP层的一个协议,但是由于差错报告在发送给报文源发方时可能也要经过若干子网,因此牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送。
ICMP数据报的数据发送前需要两级封装:
首先添加ICMP报头形成ICMP报文,再添加IP报头形成IP数据报。
TCP/IP应用于传输层之上,TCP/IP应用程序需要调用传输层的接口才能实现应用程序之间的通讯。
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。
多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。
为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。
套接字[3]接口是对网络中不同主机之间应用进程双向通信端点的抽象。
提供了应用进程利用协议栈交换数据的机制。
两个应用进程只要分别连接自己的套接字,就能方便通过计算机网络进行通信,不用去管网络的复杂结构,也不用管数据传送是复杂过程。
3、需求分析
3.1功能需求
实现的ping命令,能用于测试一个主机到另一个主机间的联通情况。
程序能实现基本的ping操作,发送ICMP回显请求报文(可以更改发送的报文数目),接收显应答报文。
显示发送数据包个数;
接收数据包个数;
丢失包个数,最大时间,最小时间以及平均时间。
3.2性能需求
能真实的的反映两台主机的联通情况
3.3界面需求
界面需要显示明确,当联通失败时能让人一眼就看出问题所在。
4系统设计及实现
4.1系统设计
创建通信的套接字-->
将地址、端口信息与套接字绑定-->
构建IP包头与ICMP包头-->
发送构建的数据包-->
接收对方主机的回应-->
给出程序反馈信息
系统执行的流程图如下图4.1所示:
图4.1
4.2系统实现
(1)模块或函数功能描述
voidping(intargc,char*argv[]):
ping()函数是本程序的核心部分,它通过调用其他模块的函数来实现,其主要步骤包括初始化winsock,初始化协议,创建套接字,名字解析。
intpack(intpack_no):
构建数据报
voidsend_packet(void):
发送数据报
voidrecv_packet(void):
接收数据报
intunpack(unsignedchar*buf,intlen):
剥去ICMP报头加显示
unsignedshortcal_checksum(unsignedshort*buffer,intsize);
//求校验和函数
voidfree():
用于释放占用的资源,包括关闭套接字和释放winsock
(2)关键的代码
IP报头字段数据结构
structIP
{
unsignedcharip_hl:
4;
//首部长度
unsignedcharip_ver:
//IP版本号
unsignedcharip_tos;
//服务类型
unsignedshortip_len;
//总长度
unsignedshortip_id;
//标识
unsignedshortip_off;
//标志位
unsignedcharip_ttl;
//生存时间
unsignedcharip_port;
//协议类型(TCP、UDP等)
unsignedshortip_checksum;
//ip首部校验和
unsignedlongip_source;
//源ip地址
unsignedlongip_dest;
//目的ip地址
};
ICMP报头字段数据结构
structICMP
{
unsignedcharicmp_type;
//消息类型
unsignedcharicmp_code;
//代码
unsignedshorticmp_checksum;
//校验和
unsignedshorticmp_id;
//用来惟一标识此请求的ID号,通常设置为进程ID
unsignedshorticmp_seq;
//序列号
unsignedlongicmp_data;
//时间戳
Ping函数
voidping(intargc,char*argv[])
WSADATAwsadata;
//WSADATA数据结构
structhostent*host;
structprotoent*protocol;
char*par_host;
par_host=argv[1];
pid=getpid();
//获取main的进程id,用于设置icmp的标志符
//使用Socket的程序在使用Socket之前必须调用WSAStartup函数完成对Winsock服务的初始化
//初始化winsock不成功
if(WSAStartup(0x1010,&
wsadata)!
=0)
{
printf("
wsastartuperror\n"
);
exit
(1);
}
//初始化协议
if((protocol=getprotobyname("
ICMP"
))==NULL)
{
getprotobynameerror\n"
}
//printf("
所选协议的协议名:
%s\n\n"
protocol->
p_name);
以主机字节顺序排列的协议号为:
%d\n\n"
p_proto);
//套接字创建不成功
if((sockfd=socket(AF_INET,SOCK_RAW,protocol->
p_proto))<
0)
socketerror\n"
//设置套接字属性
if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&
timeout,sizeof(timeout))<
fprintf(stderr,"
failedtosetrecvtimeout:
%d\n"
WSAGetLastError());
memset(&
dest_addr,0,sizeof(dest_addr));
//目的地址初始化即清零
dest_addr.sin_family=AF_INET;
//设置地址族
/*名字解析,根据IP地址获取主机名*/
if(host=gethostbyname(par_host))//par_host是ping的目的主机的ip
memcpy((char*)&
dest_addr.sin_addr,host->
h_addr,host->
h_length);
//将获取到的IP值赋给目的地地址中的相应字段
if(host=gethostbyaddr(host->
h_addr,4,PF_INET))//将ip解析为主机名
par_host=host->
h_name;
else//或者输出不明的主机
if(dest_addr.sin_addr.s_addr=inet_addr(par_host)==INADDR_NONE)
{
printf("
Unknowhost%s\n"
par_host);
exit
(1);
}
printf("
\nPinging%s[%s]with%dbytesofdata:
\n\n"
inet_ntoa(dest_addr.sin_addr),par_host,SEND_SIZE);
}
voidsend_packet()
intpacketsize;
staticintpack_no=0;
packetsize=pack(pack_no++);
//sendpacket为要发送的内容,由pack()函数设定,dest_addr是目的地址
if(sendto(sockfd,(char*)sendpacket,packetsize,0,(structsockaddr*)&
dest_addr,sizeof(dest_addr))<
0)
Destinationhostunreachable.\n"
//printf("
sendNO%d\n"
pack_no);
}
接收数据报
voidrecv_packet()
intn,fromlen;
intsuccess;
fromlen=sizeof(from_addr);
do
if((n=recvfrom(sockfd,(char*)recvpacket,sizeof(recvpacket),0,(structsockaddr*)&
from_addr,&
fromlen))>
success=unpack(recvpacket,n);
elseif(WSAGetLastError()==WSAETIMEDOUT)
{
Requesttimedout.\n"
return;
}
}while(!
success);
intpack(intpack_no)
intpacksize;