Linux网络编程之原始套接字ping协议实现Word文档格式.docx

上传人:b****3 文档编号:18414195 上传时间:2022-12-16 格式:DOCX 页数:10 大小:19.32KB
下载 相关 举报
Linux网络编程之原始套接字ping协议实现Word文档格式.docx_第1页
第1页 / 共10页
Linux网络编程之原始套接字ping协议实现Word文档格式.docx_第2页
第2页 / 共10页
Linux网络编程之原始套接字ping协议实现Word文档格式.docx_第3页
第3页 / 共10页
Linux网络编程之原始套接字ping协议实现Word文档格式.docx_第4页
第4页 / 共10页
Linux网络编程之原始套接字ping协议实现Word文档格式.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

Linux网络编程之原始套接字ping协议实现Word文档格式.docx

《Linux网络编程之原始套接字ping协议实现Word文档格式.docx》由会员分享,可在线阅读,更多相关《Linux网络编程之原始套接字ping协议实现Word文档格式.docx(10页珍藏版)》请在冰豆网上搜索。

Linux网络编程之原始套接字ping协议实现Word文档格式.docx

//校验和

union{

structih_idseq{//显示数据报

u_int16_ticd_id;

//数据报所在进程的ID

u_int16_6icd_seq;

//数据报序号

}ih_idseq;

}icmp_hun;

#defineicmp_idicmp_hun.ih_idseq.icd_id

#defineicmp_seqicmp_hun.ih_idseq.icd_seq

union{

u_int8_tid_data[i];

//数据

}icmp_dun;

#defineicmp_dataicmp_dun.id_data

}

**/

typedefstructpingm_packet{

structtimevaltv_begin;

//发送的时间

structtimevaltv_end;

//接收到响应包的时间

shortseq;

//序号值

intflag;

//1表示已经发送但没有接收到回应包,0表示接收到响应包

}pingm_packet;

//保存已经发送包的状态值

staticpingm_packetpingpacket[128];

//定义一个包数组

staticpingm_packet*icmp_findpacket(intseq);

staticunsignedshorticmp_cksum(unsignedchar*data,intlen);

staticstructtimevalicmp_tvsub(structtimevalend,structtimevalbegin);

staticvoidicmp_statistics(void);

staticvoidicmp_pack(structicmp*icmph,intseq,structtimeval*tv,intlength);

staticinticmp_unpack(char*buf,intlen);

staticvoid*icmp_recv(void*argv);

staticvoid*icmp_send(void*argv);

staticvoidicmp_sigint(intsigno);

staticvoidicmp_usage();

#defineK1024

#defineBUFFERSIZE512

staticunsignedcharsend_buff[BUFFERSIZE];

//定义发送缓冲区的大小

staticunsignedcharrecv_buff[2*K];

//定义接收缓冲区的大小,为防止接收端溢出,接收缓冲区稍微大一些

staticstructsockaddr_indest;

//目的地址

staticintrawsock=0;

//原始套接字描述符

staticpid_tpid=0;

//进程id

staticintalive=0;

//是否接收到退出信号

staticshortpacket_send=0;

//已经发送的数据包数目

staticshortpacket_recv=0;

//已经接收的数据报数目

staticchardest_str[80];

//目的主机字符串

staticstructtimevaltv_begin,tv_end,tv_interval;

//本程序开始发送,结束时间和时间间隔

staticvoidicmp_usage(){

printf("

pingaaa.bbb.ccc.ddd\n"

);

//计算ICMP首部校验和

staticunsignedshorticmp_cksum(unsignedchar*data,intlen){

intsum=0;

intodd=len&

0x01;

unsignedshort*value=(unsignedshort*)data;

while(len&

0xfffe){

sum+=*(unsignedshort*)data;

data+=2;

len-=2;

if(odd){

unsignedshorttmp=((*data)<

<

8)&

0xff00;

sum+=tmp;

sum=(sum>

>

16)+(sum&

0xffff);

sum+=(sum>

16);

return~sum;

//设置ICMP报头

staticvoidicmp_pack(structicmp*icmph,intseq,structtimeval*tv,intlength){

unsignedchari=0;

icmph->

icmp_type=ICMP_ECHO;

//ICMP回显请求

icmp_code=0;

//code为0

icmp_cksum=0;

//cksum值

icmp_seq=htons(seq);

//数据报的序列号

icmp_id=htons(pid&

//数据报的ID

for(i=0;

i<

length;

i++){

icmph->

icmp_data[i]=htons(i);

//注意主机字节序转换成网络字节序

}//发送的数据

//计算校验和

icmp_cksum=icmp_cksum((unsignedchar*)icmph,length+8);

//计算时间差函数

staticstructtimevalicmp_tvsub(structtimevalend,structtimevalbegin){

structtimevaltv;

tv.tv_sec=end.tv_sec-begin.tv_sec;

tv.tv_usec=end.tv_usec-begin.tv_usec;

if(tv.tv_usec<

0){

tv.tv_sec--;

tv.tv_usec+=1000000;

returntv;

//发送报文

staticvoid*icmp_send(void*argv){

tv.tv_usec=0;

tv.tv_sec=1;

//每隔一秒发送报文

gettimeofday(&

tv_begin,NULL);

//保存程序开始发送数据的时间

while(alive){

memset(send_buff,0,sizeof(send_buff));

intsize=0;

tv,NULL);

//当前包发送的时间

icmp_pack((structicmp*)send_buff,packet_send,&

tv,203);

//packet_send为发送包的序号,发送的数据长度为64个字节,填充ICMP首部信息

size=sendto(rawsock,send_buff,203+8,0,(structsockaddr*)&

dest,sizeof(dest));

//dest为ICMP包发送的目的地址

if(size<

perror("

sendtoerror"

continue;

}

else{

//在发送包的状态数组找一空闲位置记录发送状态信息

pingm_packet*packet=icmp_findpacket(-1);

if(packet){

packet->

seq=packet_send;

flag=1;

packet->

packet_send++;

//发送序号+1

sleep

(1);

//寻找一个空闲位置,seq=-1表示空闲位置

staticpingm_packet*icmp_findpacket(intseq){

inti=0;

pingm_packet*found=NULL;

if(seq==-1){

for(i=0;

128;

if(pingpacket[i].flag==0){

found=&

pingpacket[i];

break;

}elseif(seq>

=0){//查找对应seq的数据包

if(pingpacket[i].seq==seq){

 

break;

returnfound;

//获得ICMP接收报文,buf存放的除去了以太网部分的IP数据报文,len为数据长度,ip_hl标识IP头部长度以4字节为单位,获得ICMP数据报后判断是否为ICMP_ECHOREPLY并检查是否为本进程的ID

staticinticmp_unpack(char*buf,intlen){

inti,iphdrlen;

structip*ip=NULL;

structicmp*icmp=NULL;

intrtt;

//计算往返时延

ip=(structip*)buf;

iphdrlen=ip->

ip_hl*4;

//IP头部长度

icmp=(structicmp*)(buf+iphdrlen);

//ICMP报文的地址

len-=iphdrlen;

//ICMP报文的长度,ICMP报文至少8个字节

if(len<

8){

printf("

ICMPpackets\'

slengthislessthan8\n"

return-1;

//判断ICMP报文的类型是否为ICMP_ECHOREPLY并且为本进程的PID

if((icmp->

icmp_type==ICMP_ECHOREPLY)&

&

(icmp->

icmp_id==pid)){

structtimevaltv_interval,tv_recv,tv_send;

//在发送数组中查找已经发送的包

pingm_packet*packet=icmp_findpacket(ntohs(icmp->

icmp_seq));

//网络字节序转换成主机字节序

if(packet==NULL){

return-1;

flag=0;

//表示已经响应了

//本包的发送时间

tv_send=packet->

tv_begin;

//读取收到响应包的时间

gettimeofday(&

tv_recv,NULL);

tv_interval=icmp_tvsub(tv_recv,tv_send);

//计算往返时延,即RTT

rtt=tv_interval.tv_sec*1000+tv_interval.tv_usec/1000;

//打印ICMP段长度,源IP,包的序列号,TTL,时间差

%dbytefrom%s:

icmp_seq=%uttl=%drtt=%dms\n"

len,inet_ntoa(ip->

ip_src),icmp->

icmp_seq,ip->

ip_ttl,rtt);

packet_recv++;

//接收包的数量加1

else{

//接收报文

staticvoid*icmp_recv(void*argv){

structtimevaltv;

tv.tv_usec=200;

//轮循时间

tv.tv_sec=0;

fd_setreadfd;

while(alive){

intret=0;

tv.tv_usec=200;

tv.tv_sec=0;

FD_ZERO(&

readfd);

FD_SET(rawsock,&

ret=select(rawsock+1,&

readfd,NULL,NULL,&

tv);

intfromlen=0;

structsockaddrfrom;

switch(ret){

case-1:

//发生错误

case0:

//超时

//printf("

timeout\n"

default:

//收到数据包

fromlen=sizeof(from);

intsize=recvfrom(rawsock,recv_buff,sizeof(recv_buff),0,(structsockaddr*)&

from,&

fromlen);

//利用原始套接字,原始套接字与IP层网络协议栈核心打交道

if(errno==EINTR){

recvfromerror"

//解包,得到RTT

ret=icmp_unpack(recv_buff,size);

if(ret==-1){

//统计数据结果,成功发送的报文数量,成功接收的报文数量,丢失报文百分比和程序总共运行时间

staticvoidicmp_statistics(void){

longtime=(tv_interval.tv_sec*1000)+(tv_interval.tv_usec/1000);

---%spingstatistics---\n"

dest_str);

//目的IP

%dpacketstransmitted,%drecevied,%d%cpacketloss,time%dms\n"

packet_send,packet_recv,(packet_send-packet_recv)*100/packet_send,'

%'

time);

//信号处理函数

staticvoidicmp_sigint(intsigno){

alive=0;

//alive=0程序将会终止

tv_end,NULL);

//程序结束时间

tv_interval=icmp_tvsub(tv_end,tv_begin);

//计算程序一共运行了多长时间

return;

//主函数实现

intmain(intargc,char*argv[]){

structhostent*host=NULL;

structprotoent*protocol=NULL;

charprotoname[]="

icmp"

;

unsignedlonginaddr=1;

intsize=128*K;

intret;

if(argc<

2){

icmp_usage();

//获取协议类型ICMP,协议类型的值作为设置原始套接字的第3个参数,type类型下的具体协议值不止一个,当type为SOCK_RAW

protocol=getprotobyname(protoname);

if(protocol==NULL){

getprotobyname()"

//复制目的地址

memcpy(dest_str,argv[1],strlen(argv[1])+1);

memset(pingpacket,0,sizeof(pingm_packet)*128);

//pingpacket数组初始化

//建立原始套接字

rawsock=socket(AF_INET,SOCK_RAW,protocol->

p_proto);

if(rawsock<

rawsockerror"

//得到程序的pid

pid=getuid();

//增大接收端缓冲区防止接收的包被覆盖

ret=setsockopt(rawsock,SOL_SOCKET,SO_RCVBUF,&

size,sizeof(size));

SO_RCVBUFERROR"

//输入的目的IP

inaddr=inet_addr(argv[1]);

//转换成二进制IP

bzero(&

dest.sin_family=AF_INET;

//设置地址族

if(inaddr==INADDR_NONE){

//输入的是DNS

host=gethostbyname(argv[1]);

if(host==NULL){

gethostbyname"

memcpy((char*)&

dest.sin_addr,host->

h_addr,host->

h_length);

dest.sin_addr,&

inaddr,sizeof(inaddr));

inaddr=dest.sin_addr.s_addr;

//由于是ICMP不涉及到端口绑定

PING%s(%d.%d.%d.%d)56(84)bytesofdata.\n"

dest_str,(inaddr&

0x000000FF)>

0,(inaddr&

0x0000FF00)>

8,(inaddr&

0x00FF0000)>

16,(inaddr&

0xFF000000)>

24);

signal(SIGINT,icmp_sigint);

alive=1;

//定义两个线程,分别用于发送数据与接收数据

pthread_tsend_id,recv_id;

interr=0;

err=pthread_create(&

send_id,NULL,icmp_send,NULL);

if(err<

recv_id,NULL,icmp_recv,NULL);

pthread_join(send_id,NULL);

//等待子线程结束send

pthread_join(recv_id,NULL);

//等待子线程的结束recv

close(rawsock);

icmp_statistics();

return0;

运行结果:

PING222.27.253.1(222.27.253.1)56(84)bytesofdata.

60bytefrom222.27.253.1:

icmp_seq=0ttl=255rtt=5ms

icmp_seq=1ttl=255rtt=12ms

icmp_seq=2ttl=255rtt=5ms

icmp_seq=3ttl=255rtt=7ms

icmp_seq=4ttl=255rtt=2ms

icmp_seq=5ttl=255rtt=23ms

icmp_seq=6ttl=255rtt=27ms

icmp_seq=7ttl=255rtt=10ms

icmp_seq=8ttl=255rtt=17ms

icmp_seq

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

当前位置:首页 > 医药卫生 > 基础医学

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

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