Linux下Socket网络编程中ICMP的应用 (linux socket icmp)

随着互联网技术的不断发展,网络编程已成为了计算机科学不可或缺的一部分。而作为一个网络编程工程师,学习套接字编程是十分必要的。Linux下Socket网络编程可以说是互联网通信的基础,而网络通信中的ICMP协议,则是套接字编程的核心。

一、 ICMP简介

Internet 控制消息协议(Internet Control Message Protocol,简称 ICMP)是 TCP/IP 协议族的重要组成部分,用于网络设备之间进行错误报告传递、交换网络状态信息等。常常被用于网络管理、网络故障排查等领域,在网络编程中也广泛应用。

ICMP主要分为两类:一种是错误报告 ICMP 错误消息,另一种则是一些辅助信息 ICMP通知消息。在套接字编程中经常使用的,是ICMP错误消息,例如路由器发送 ICMP 给发送数据的主机,使其知道到达的地址不可达。

二、 套接字编程下的ICMP应用

在 Linux 下套接字编程中,ICMP 错误消息的处理是由内核完成的,而应用程序通过捕获对应的 ICMP 错误消息进行处理。这种方式被称为”Socket接收错误报告”。在套接字编程中,如果应用程序向一个未连接的IP地址发送数据,而这个IP地址无法到达,那么内核会自动回复一个 ICMP “目的地不可达”的信息。而我们可以通过捕捉这个回复信息,得知目的IP地址是否可达。

下面是一个ICMP的应用例程:

“`

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PACKET_SIZE 4096

#define MAX_WT_TIME 5

#define MAX_NO_PACKETS 3

char sendpacket[PACKET_SIZE];

char recvpacket[PACKET_SIZE];

int sockfd,datalen = 56;

int nsend = 0,nreceived = 0;

struct sockaddr_in dest_addr;

struct sockaddr_in from;

unsigned short cal_chksum(unsigned short *addr,int len);

int pack(int pack_no)

{

int i,packsize;

struct icmp *icmp;

struct timeval *tval;

icmp = (struct icmp*)sendpacket;

icmp->icmp_type = ICMP_ECHO;

icmp->icmp_code = 0;

icmp->icmp_cksum = 0;

icmp->icmp_seq = pack_no;

icmp->icmp_id = getpid();

packsize = 8 + datalen;

tval = (struct timeval *)icmp->icmp_data;

gettimeofday(tval,NULL);

icmp->icmp_cksum = cal_chksum((unsigned short *)icmp,packsize);

return packsize;

}

void send_packet()

{

int packetsize;

while(nsend

nsend++;

packetsize = pack(nsend);

if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))

perror(“sendto error”);

continue;

}

}

}

void recv_packet()

{

int n,fromlen;

extern int errno;

fromlen = sizeof(from);

while(nreceived

if((n = recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from,&fromlen))

if(errno == EINTR)

continue;

perror(“recvfrom error”);

continue;

}

gettimeofday(&tvrecv,NULL);

unpack(recvpacket,n);

nreceived++;

}

}

int unpack(char *buf,int len)

{

int i,iphdrlen;

struct iphdr *ip;

struct icmp *icmp;

struct timeval *tvsend;

double rtt;

ip = (struct iphdr *)buf;

iphdrlen = ip->ihl

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

len -= iphdrlen;

if(len

fprintf(stderr,”ICMP packets\’s length is less than 8\n”);

return -1;

}

if((icmp->icmp_type == ICMP_ECHOREP) && (icmp->icmp_id == getpid())){

tvsend = (struct timeval *)icmp->icmp_data;

tv_sub(&tvrecv,tvsend);

rtt = tvrecv.tv_sec * 1000 + tvrecv.tv_usec / 1000.0;

printf(“%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms\n”,len,inet_ntoa(from.sin_addr),icmp->icmp_seq,ip->ttl,rtt);

}else{

printf(“none %d byte ICMP packet received from %s icmp_type=%d icmp_code=%d\n”,len,inet_ntoa(from.sin_addr),icmp->icmp_type,icmp->icmp_code);

}

}

unsigned short cal_chksum(unsigned short *addr,int len)

{

int nleft = len;

int sum = 0;

unsigned short *w = addr;

unsigned short answer = 0;

while(nleft > 1){

sum += *w++;

nleft -= 2;

}

if(nleft == 1){

*(unsigned char *)(&answer) = *(unsigned char *)w;

sum += answer;

}

sum = (sum >> 16) + (sum & 0xffff);

sum += (sum >> 16);

answer = ~sum;

return answer;

}

int mn(int argc,char *argv[])

{

struct hostent *host;

struct timeval tv;

struct timezone tz;

int ch;

char buf[128];

opterr = 0;

while((ch = getopt(argc,argv,”t:”)) != -1){

switch(ch){

case ‘t’:

if(optarg == NULL){

fprintf(stderr,”Please input IP addresss or domn name.\n”);

exit(1);

}

if((host = gethostbyname(optarg)) == NULL){

perror(“gethostbyname error”);

exit(1);

}

break;

default:

printf(“-t \n”);

exit(1);

}

}

argc -= optind;

argv += optind;

if(argc != 0){

printf(“Usage:%s -t \n”,argv[0]);

exit(1);

}

if(host == NULL){

printf(“Please input IP addresss or domn name.\n”);

exit(1);

}

memset(&dest_addr,0,sizeof(dest_addr));

dest_addr.sin_family = AF_INET;

memcpy(&dest_addr.sin_addr,host->h_addr,host->h_length);

dest_addr.sin_port = htons(0);

if((sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))

perror(“socket error”);

exit(1);

}

setuid(getpid());

printf(“PING %s (%s): %d data bytes\n”,host->h_name,inet_ntoa(dest_addr.sin_addr),datalen);

send_packet();

recv_packet();

printf(“\n— %s ping statistics —\n”,host->h_name);

printf(“%d packets tranitted, %d received, %%%d lost\n”,nsend,nreceived,(nsend-nreceived)/nsend*100);

return 0;

}

“`

这个例程是一个简单的Ping程序,可以根据域名或者IP地址获取目标主机的回应时间。该程序主要分为三个部分:发送数据包、接收错误报告、打印数据统计信息。

三、 一些需要注意的问题

在套接字编程中,需要注意以下问题:

1. 要使用ICMP协议,需要使用SOCK_RAW套接字类型,需要root权限运行。

2. 注意ICMP报文的格式,不同类型的ICMP报文格式不同,需要仔细调查。

3. 在接收ICMP错误报告时,需要注意可能会同时收到发送的数据包和接收的错误报告。因此需要仔细分析收到的数据包,以确定错误信息的来源。

相关问题拓展阅读:

100分求linux下C语言端口扫描代码

linux tcp udp 端口扫描源程序

#include

#include

#include

#include

#include

#include

#include

#include 做庆

#include

#include

#include

#include

#include

#define TRUE

#define FALSE 0

#define UDP”UDP”

#define TCP”TCP”

#define tcp”tcp”

#define udp”udp”

typedef struct _GsSockStru{

int fd;

int len;

struct sockaddr_in addr;

}GsSockStru;

static int tcptest( char ip, char port);

static int udptest( char ip, char port);

voidsig_alrm( int signo );

static GsSockStru test_sock;

int

main( int argc, char** argv)

{

char string;

char port;

char pro;

char ip;

intres;

inti = 0;

intk = 0;

if( argc>2 || argctype ==&& icmp_header->code

{

printf(“Port %d : Close\n”,scan_port);

return (0);

}

}

return (1) ;

}

}

linux socket icmp的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux socket icmp,Linux下Socket网络编程中ICMP的应用,100分求linux下C语言端口扫描代码的信息别忘了在本站进行查找喔。


数据运维技术 » Linux下Socket网络编程中ICMP的应用 (linux socket icmp)