
随着互联网技术的不断发展,网络编程已成为了计算机科学不可或缺的一部分。而作为一个网络编程工程师,学习套接字编程是十分必要的。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语言端口扫描代码
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语言端口扫描代码的信息别忘了在本站进行查找喔。
香港服务器首选树叶云,2H2G首月10元开通。
树叶云(www.IDC.Net)提供简单好用,价格厚道的香港/美国云服务器和独立服务器。IDC+ISP+ICP资质。ARIN和APNIC会员。成熟技术团队15年行业经验。
文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/182773.html<