ImageVerifierCode 换一换
格式:DOCX , 页数:10 ,大小:19.32KB ,
资源ID:5426679      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5426679.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Linux网络编程之原始套接字ping协议实现.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Linux网络编程之原始套接字ping协议实现.docx

1、Linux网络编程之原始套接字ping协议实现1.概述PING协议是用来检验本地主机与远程主机是否连接,发送的是ICMP ECHO_REQUEST包。普通的套接字是基于TCP或者是UDP的,无法发送ICMP包,所以必须用原始套接字来实现。PING协议的客户端类型值为8,代码值为0,表示请求。而PING协议的响应端类型值为0,代码值也为0,表示应答. 以太网数据部分的最小值为46字节,而IP首部占20个字节,ICMP的首部占8个字节,所以PING的数据部分至少为4字节。2.实现细节主机端:(1)创建原始套接字 socket(AF_INET,SOCK_RAW,htons(proto),能够直接得到

2、IP包(2)填写ICMP首部和数据部分,即icmp_type(8),icmp_code(0)和icmp_data部分(3)封装后发送ICMP请求包响应端:(1)创建原始套接字socket(AF_INET,SOCK_RAW,htons(proto)(2)填写ICMP首部和数据部分,即icmp_type(0),icmp_code(0),icmp_data(3)发送ICMP响应包主机端收到ICMP响应包之后,即原始的IP包,将收到包的时间减去包的发送时间就可以得到响应时延。3. PING协议的实现例子#include #include #include #include #include #incl

3、ude #include #include #include #include #include #include #include #include /*通过原始套接字发送ICMP回显请求报文来实现ping协议ICMP回显报文的结构struct icmp u_int8_t icmp_type;/消息类型 u_int8_t icmp_code;/消息类型的子码 u_int16_t icmp_cksum;/校验和 union struct ih_idseq/显示数据报 u_int16_t icd_id;/数据报所在进程的ID u_int16_6 icd_seq;/数据报序号ih_idseq;ic

4、mp_hun;#define icmp_id icmp_hun.ih_idseq.icd_id#define icmp_seq icmp_hun.ih_idseq.icd_sequnionu_int8_t id_datai;/数据icmp_dun;#define icmp_data icmp_dun.id_data*/typedef struct pingm_packet struct timeval tv_begin;/发送的时间 struct timeval tv_end;/接收到响应包的时间 short seq;/序号值 int flag;/1表示已经发送但没有接收到回应包,0表示接收到

5、响应包pingm_packet;/保存已经发送包的状态值static pingm_packet pingpacket128;/定义一个包数组static pingm_packet *icmp_findpacket(int seq);static unsigned short icmp_cksum(unsigned char*data,int len);static struct timeval icmp_tvsub(struct timeval end,struct timeval begin);static void icmp_statistics(void);static void icm

6、p_pack(struct icmp*icmph,int seq,struct timeval *tv,int length);static int icmp_unpack(char*buf,int len);static void* icmp_recv(void*argv);static void* icmp_send(void*argv);static void icmp_sigint(int signo);static void icmp_usage();#define K 1024#define BUFFERSIZE 512static unsigned char send_buffB

7、UFFERSIZE;/定义发送缓冲区的大小static unsigned char recv_buff2*K;/定义接收缓冲区的大小,为防止接收端溢出,接收缓冲区稍微大一些static struct sockaddr_in dest;/目的地址static int rawsock=0;/原始套接字描述符static pid_t pid=0;/进程idstatic int alive=0;/是否接收到退出信号static short packet_send=0;/已经发送的数据包数目static short packet_recv=0;/已经接收的数据报数目static char dest_st

8、r80;/目的主机字符串static struct timeval tv_begin,tv_end,tv_interval;/本程序开始发送,结束时间和时间间隔static void icmp_usage()printf(ping aaa.bbb.ccc.dddn);/计算ICMP首部校验和static unsigned short icmp_cksum(unsigned char* data,int len)int sum=0;int odd=len&0x01;unsigned short *value=(unsigned short*)data;while(len&0xfffe) sum+

9、=*(unsigned short*)data; data+=2; len-=2;if(odd) unsigned short tmp=(*data)16)+(sum&0xffff);sum+=(sum16);return sum;/设置ICMP报头static void icmp_pack(struct icmp *icmph,int seq,struct timeval*tv,int length)unsigned char i=0;icmph-icmp_type=ICMP_ECHO;/ICMP回显请求icmph-icmp_code=0;/code为0icmph-icmp_cksum=0;

10、/cksum值icmph-icmp_seq=htons(seq);/数据报的序列号icmph-icmp_id=htons(pid&0xffff);/数据报的IDfor(i=0;iicmp_datai=htons(i);/注意主机字节序转换成网络字节序/发送的数据/计算校验和icmph-icmp_cksum=icmp_cksum(unsigned char*)icmph,length+8);/计算时间差函数static struct timeval icmp_tvsub(struct timeval end,struct timeval begin) struct timeval tv; tv.

11、tv_sec=end.tv_sec-begin.tv_sec; tv.tv_usec=end.tv_usec-begin.tv_usec; if(tv.tv_usec0) tv.tv_sec-; tv.tv_usec+=1000000; return tv;/发送报文static void *icmp_send(void *argv) struct timeval tv; tv.tv_usec=0; tv.tv_sec=1;/每隔一秒发送报文 gettimeofday(&tv_begin,NULL);/保存程序开始发送数据的时间 while(alive) memset(send_buff,0,

12、sizeof(send_buff); int size=0; struct timeval tv; gettimeofday(&tv,NULL);/当前包发送的时间 icmp_pack(struct icmp*)send_buff,packet_send,&tv,203);/packet_send为发送包的序号,发送的数据长度为64个字节,填充ICMP首部信息 size=sendto(rawsock,send_buff,203+8,0,(struct sockaddr*)&dest,sizeof(dest);/dest为ICMP包发送的目的地址 if(sizeseq=packet_send;

13、packet-flag=1; gettimeofday(&packet-tv_begin,NULL); packet_send+;/发送序号1 sleep(1);/寻找一个空闲位置,seq=-1表示空闲位置static pingm_packet* icmp_findpacket(int seq) int i=0; pingm_packet* found=NULL; if(seq=-1) for(i=0;i=0)/查找对应seq的数据包 for(i=0;iip_hl*4;/IP头部长度 icmp=(struct icmp*)(buf+iphdrlen);/ICMP报文的地址 len-=iphdr

14、len;/ICMP报文的长度,ICMP报文至少8个字节 if(lenicmp_type=ICMP_ECHOREPLY)&(icmp-icmp_id=pid) struct timeval tv_interval,tv_recv,tv_send;/在发送数组中查找已经发送的包pingm_packet*packet=icmp_findpacket(ntohs(icmp-icmp_seq);/网络字节序转换成主机字节序if(packet=NULL)return -1;packet-flag=0;/表示已经响应了/本包的发送时间tv_send=packet-tv_begin;/读取收到响应包的时间ge

15、ttimeofday(&tv_recv,NULL);tv_interval=icmp_tvsub(tv_recv,tv_send);/计算往返时延,即RTTrtt=tv_interval.tv_sec*1000+tv_interval.tv_usec/1000;/打印ICMP段长度,源IP,包的序列号,TTL,时间差printf(%d byte from %s:icmp_seq=%u ttl=%d rtt=%d msn,len,inet_ntoa(ip-ip_src),icmp-icmp_seq,ip-ip_ttl,rtt);packet_recv+;/接收包的数量加1elsereturn -

16、1;/接收报文static void *icmp_recv(void*argv)struct timeval tv;tv.tv_usec=200;/轮循时间tv.tv_sec=0;fd_set readfd;while(alive) int ret=0; tv.tv_usec=200;/轮循时间 tv.tv_sec=0; FD_ZERO(&readfd); FD_SET(rawsock,&readfd); ret=select(rawsock+1,&readfd,NULL,NULL,&tv); int fromlen=0; struct sockaddr from; switch(ret)ca

17、se -1:/发生错误break;case 0:/超时/printf(timeoutn);break;default:/收到数据包fromlen=sizeof(from);int size=recvfrom(rawsock,recv_buff,sizeof(recv_buff),0,(struct sockaddr*)&from,&fromlen);/利用原始套接字,原始套接字与IP层网络协议栈核心打交道if(errno=EINTR) perror(recvfrom error);/解包,得到RTTret=icmp_unpack(recv_buff,size);if(ret=-1) conti

18、nue;break;/统计数据结果,成功发送的报文数量,成功接收的报文数量,丢失报文百分比和程序总共运行时间static void icmp_statistics(void) long time=(tv_interval.tv_sec*1000)+(tv_interval.tv_usec/1000); printf(- %s ping statistics -n,dest_str);/目的IP printf(%d packets transmitted, %d recevied, %d%c packet loss, time %d msn,packet_send,packet_recv,(pa

19、cket_send-packet_recv)*100/packet_send,%,time);/信号处理函数static void icmp_sigint(int signo) alive=0;/alive=0程序将会终止 gettimeofday(&tv_end,NULL);/程序结束时间 tv_interval=icmp_tvsub(tv_end,tv_begin);/计算程序一共运行了多长时间 return;/主函数实现int main(int argc,char*argv) struct hostent *host=NULL; struct protoent*protocol=NULL

20、; char protoname=icmp; unsigned long inaddr=1; int size=128*K; int ret;if(argcp_proto);if(rawsockh_addr,host-h_length);elsememcpy(char*)&dest.sin_addr,&inaddr,sizeof(inaddr);inaddr=dest.sin_addr.s_addr;/由于是ICMP不涉及到端口绑定printf(PING %s (%d.%d.%d.%d) 56(84)bytes of data.n,dest_str,(inaddr&0x000000FF)0,(

21、inaddr&0x0000FF00)8,(inaddr&0x00FF0000)16,(inaddr&0xFF000000)24);signal(SIGINT,icmp_sigint);alive=1;/定义两个线程,分别用于发送数据与接收数据pthread_t send_id,recv_id;int err=0;err=pthread_create(&send_id,NULL,icmp_send,NULL);if(err0) return -1;err=pthread_create(&recv_id,NULL,icmp_recv,NULL);if(err0) return -1;pthread

22、_join(send_id,NULL);/等待子线程结束sendpthread_join(recv_id,NULL);/等待子线程的结束recvclose(rawsock);icmp_statistics();return 0;运行结果:PING 222.27.253.1 (222.27.253.1) 56(84)bytes of data.60 byte from 222.27.253.1:icmp_seq=0 ttl=255 rtt=5 ms60 byte from 222.27.253.1:icmp_seq=1 ttl=255 rtt=12 ms60 byte from 222.27.2

23、53.1:icmp_seq=2 ttl=255 rtt=5 ms60 byte from 222.27.253.1:icmp_seq=3 ttl=255 rtt=7 ms60 byte from 222.27.253.1:icmp_seq=4 ttl=255 rtt=2 ms60 byte from 222.27.253.1:icmp_seq=5 ttl=255 rtt=23 ms60 byte from 222.27.253.1:icmp_seq=6 ttl=255 rtt=27 ms60 byte from 222.27.253.1:icmp_seq=7 ttl=255 rtt=10 ms60 byte from 222.27.253.1:icmp_seq=8 ttl=255 rtt=17 ms60 byte from 222.27.253.1:icmp_seq

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

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