网络编程-PING程序设计实验指导书
一.实验目的
(1)熟悉原始套接字编程。
(2)了解网络的结构。
(3)了解网络传输底层协议。
二.实验要求
PING程序是用于测试网络连通性的程序。要求在WINDOWS环境下实现基本的PING程序功能.
在命令提示符下输入:
PING ***.***.***.***
其中***为目的主机的IP地址,不要求支持域名,对是否带有开关变量也不做要求。不带开关变量时,要求返回4次响应。
返回信息的格式:
REPLY FROM ***.***.***.***
或
REQUEST TimeOut (无法PING通的情况)
三.实验原理
1、PING的工作原理
ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。ping 使用的是ICMP协议,它发送ICMP回送请求消息给目的主机。ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。
ICMP协议通过IP协议发送的,IP协议是一种无连接的,不可靠的数据包协议。因此,保证数据送达的工作应该由其他的模块来完成。其中一个重要的模块就是ICMP(网络控制报文)协议。
当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机。给主机一个处理错误的机会,这也就是为什么说建立在IP层以上的协议是可能做到安全的原因。ICMP数据包由8bit的错误类型和8bit的代码和16bit的校验和组成。而前 16bit就组成了ICMP所要传递的信息。
PING利用ICMP协议包来侦测另一个主机是否可达。原理是用类型码为0的ICMP发请求,受到请求的主机则用类型码为8的ICMP回应。ping程序来计算间隔时间,并计算有多少个包被送达。用户就可以判断网络大致的情况。
IP数据报
TCP/IP协议定义了一个在因特网上传输的包, 称为IP数据报(IP datagram). 这是一个与硬件无关的虚拟包, 由包头和数据两部分组成, 包头中的源地址和目的地址都是IP协议地址.
ICMP
TCP/IP组件包括一个ICMP(Internet Control Message Protocol)协议, 该协议定义了的报文类型: Echo,Echo Reply,用于ping程序的基本实现
下图是ICMP报文的传送:2、RAW模式的SOCKET编程
PING程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。为了实现直接对IP和ICMP包进行操作,实验中使用RAW模式的SOCKET编程。
熟悉SOCKET的编程,包括基本的系统调用如SOCKET、BIND等.
3、具体内容
(1) 定义数据结构
需要定义好IP数据报、ICMP包等相关的数据结构
(2) 程序实现
在WINDOWS环境下实现PING程序
四. 实验步骤和注意事项
1、 熟悉IP以及ICMP协议的工作机制
2、 熟悉RAW模式的SOCKET编程
3、编写PING的实现程序
4、编译环境中需要包括SOCKET库 WS2_32.lib
5、 在模拟实现环境下调试并运行自己编写的PING程序
6、最后提交源程序,撰写实验报告
初步流程图
具体步骤
1、定义IP头和ICMP头
该程序定义自己的IP头和ICMP头数据结构,代码如下:
//IP首部数据结构
typedef struct iphdr
{
unsigned int h_len : 4 ; //首部长度
unsigned int version : 4 ; //版本
unsigned char tos ; //服务类型
unsigned short total_len ; //报文总长度
unsigned short ident ; //标识
unsigned short frag_and_flags ; //偏移量
unsigned char ttl ; //寿命
unsigned char proto ; //协议
unsigned short checksum ;// 首部校验和
unsigned int sourceIP ;// 源站IP
unsigned int destIP ;// 目的站IP
};
//ICMP首部数据结构
typedef struct icmphdr
{
BYTE i_type ; //类型
BYTE i_code ; //代码
USHORT i_cksum ; //首部校验和
USHORT i_id ; //标识
USHORT i_seq ; //序列号
ULONG timestamp ; //时间戳
};
2.定义变量
WSADATA wsaData ;
SOCKET sockRaw ;
struct sockaddr_in dest,from ;
struct hostent*hp ;
int bread,datasize=32,packnum=6;
int fromlen=sizeof(from);
int timeout=1000 ;
int statistic=0 ;
int ts=0;
char*dest_ip ;
char*icmp_data ;
char*recvbuf ;
unsigned int addr=0 ;
USHORT seq_no=0 ;
int temp;
3、定义函数:
(1)void fill_icmp_data(char*icmp_data,int datasize,int ts);
//填充ICMP报头
void fill_icmp_data(char*icmp_data,int datasize,int ts)
{
IcmpHeader*icmp_hdr ;
char*datapart ;
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 ;
icmp_hdr->timestamp=ts;
datapart=icmp_data+sizeof(IcmpHeader);
memset(datapart,'E',datasize-sizeof(IcmpHeader));
}
(2)USHORT checksum(USHORT*buffer,int size);
//计算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);
}
(3)int decode_resp(char*buf,int bytes,struct sockaddr_in*from);
//解析收到的数据包
int decode_resp(char*buf,int bytes,struct sockaddr_in*from)
{
IpHeader*iphdr ;
IcmpHeader*icmphdr ;
unsigned short iphdrlen ;
iphdr=(IpHeader*)buf ;
iphdrlen=(iphdr->h_len)*4 ;
if(bytes<iphdrlen+ICMP_MIN)
{
cout<<"Too few bytes from "<<inet_ntoa(from->sin_addr)<<endl;
}
icmphdr=(IcmpHeader*)(buf+iphdrlen);
if(icmphdr->i_type!=ICMP_ECHOREPLY)
{
cout<<"non-echo type "<<icmphdr->i_type<<" recvd\n";
return 1 ;
}
if(icmphdr->i_id!=(USHORT)GetCurrentProcessId())
{
cout<<"someone else's packet!\n";
return 1 ;
}
bytes-=32;
cout<<"Reply from "<<inet_ntoa(from->sin_addr)<<":"<<" bytes:"<<bytes;
cout<<" packnum = "<<icmphdr->i_seq+1<<".";
cout<<" time: "<<GetTickCount()-icmphdr->timestamp<<" ms "<<endl;
return 0 ;
}
4.主函数的具体流程(int main(
1)原始套接字的创建:
SOCKET sockRaw ;
sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED;
if(sockRaw==INVALID_SOCKET)
{
cout<<"WSASocket() failed: "<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
2)定义套接字选项
bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));如果没有出现错误,setsocket返回值为0;
3)定义sockaddr_in类型的dest,from两个变量。
sock addr_in结构是专门被Windows Sockets用来详细说明套接字连接地址的。
struct sockaddr_in dest,from;
struct hostent*hp;
char*dest_ip ;//用来放要ping的目的地址。
if(hp!=NULL)
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
else
dest.sin_addr.s_addr=addr ;
if(hp)
dest.sin_family=hp->h_addrtype ;
else
dest.sin_family=AF_INET ;
dest_ip=inet_ntoa(dest.sin_addr);
4)创建ICMP包
datasize+=sizeof(IcmpHeader);
icmp_data=(char*)xmalloc(MAX_PACKET);
recvbuf=(char*)xmalloc(MAX_PACKET);
if(!icmp_data)
{
cout<<"HeapAlloc failed "<<GetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
memset(icmp_data,0,MAX_PACKET);
fill_icmp_data(icmp_data,datasize,ts);//函数已经在前面定义
5)发送和接收ICMP包
for(int i=0;i < packnum;++i)
{
int bwrote ;
((IcmpHeader*)icmp_data)->i_cksum=0 ;
((IcmpHeader*)icmp_data)->timestamp=GetTickCount();
((IcmpHeader*)icmp_data)->i_seq=seq_no++;
((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,datasize);
//checksum用来计算校验和,函数已经在前面定义。
bwrote=sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));//sendto用来发送数据到指定的地址。
if(bwrote==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"Request timed out.\n";
continue ;
}
cout<<"sendto failed: "<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
if(bwrote<datasize)
{
cout<<"Wrote "<<bwrote<<" bytes\n";
}
bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);// recvfrom用来接收数据并保存
//bread changed
if(bread==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"Request timed out.\n";
continue ;
}
cout<<"recvfrom failed: "<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
if(!decode_resp(recvbuf,bread,&from))
//decode_resp用来解析收到的ICMP数据包,函数已经在前面定义。
statistic++;
Sleep(1000);
}
6)输出统计结果
五、程序实现的结果:
在运行程序时,要选择菜单“工程→设置 →Link”,在对象/库模块中添加Ws2_32.lib,如下图:
在DOS窗口下到ping.exe的当前目录下,输入ping,如下图:
若输入ping 172.24.218.166,如下图:
若输入ping 172.24.218.166 –l 88 –n 8,如下图:
若输入ping 172.24.218.166 –s 20## –w 20## –l 88 –n 8,如下图:
输入ping 172.22.218.18,如下图:
实 验 报 告
网络编程课程设计报告题目姓名学院专业班级学号指导教师基于Linux网络聊天室的设计陈佳悦陈雄兰信息科学技术学院网络工程网络工程10…
武汉理工大学学生实验报告书实验课程名称网络软件编程技术开课学院计算机科学与技术学院指导老师姓名学生姓名学生专业班级软件sy1101…
20xx年秋季学期计算机网络编程实验报告班级计121班学号12101020xx8姓名刘杰总成绩评语指导教师签字日期实验一登陆页面及…
计算机科学与工程学院网络工程专业20XX级网络编程实验大作业报告网络编程实验大作业报告即时通讯软件的设计与实现完成日期20xx41…
实验一TCPSocketAPI程序设计一预备知识1网络编程基本概念网络上的计算机间的通讯实质上是网络中不同主机上的程序之间的通讯在…
Windows网络程序设计课程设计课程名称ping程序设计姓名马杰尤文韬伍睿潘海涛系别专业计算机科学系网络工程一班导师姓名职称曹清…
电子科技大学实验报告学号20xx019xx0027学生姓名李贝课程名称任课老师张科实验项目名称排错工具Ping和Trace实验2排…
一实验目的PING程序是我们使用的比较多的用于测试网络连通性的程序PING程序基于ICMP使用ICMP的回送请求和回送应答来工作由…
计算机网络实验报告实验步骤一12关闭windows防火墙利用ping命令向几个站点发送信息例如ping192168311273使用…
嵌入式实验报告题目linux串口和网络编程一实验目的1强化本学期所学的相关的内容2掌握串口相关设置3强化基于TCP网络传输的三次握…