加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

Linux用ICMP协议达成简单Ping网络监测功能

发布时间:2021-11-23 15:59:06 所属栏目:教程 来源:互联网
导读:ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是

ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
 
ICMP协议是一种面向无连接的协议,用于传输出错报告控制信息。它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
 
折腾半天,原来ICMP也是TCP/IP其中一种协议.那么监测网络是否ping的通,就跟TCP协议差不多了。
 
步骤简单归纳为:1.绑定套接字,2.发送数据包 3.接收数据包 4.解析数据包
#include <stdio.h>   
#include <sys/socket.h>   
#include <netinet/in.h>   
#include <netinet/ip.h>   
#include <netinet/ip_icmp.h>   
#include <netdb.h>  
 
#define PACKET_SIZE     4096   
#define ERROR           0   
#define SUCCESS         1   
  
//效验算法(百度下有注释,但是还是看不太明白)   
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;  
}  
// Ping函数   
int ping( char *ips, int timeout)    
{        
    struct timeval *tval;          
    int maxfds = 0;    
    fd_set readfds;    
      
    struct sockaddr_in addr;    
    struct sockaddr_in from;    
    // 设定Ip信息     
    bzero(&addr,sizeof(addr));    
    addr.sin_family = AF_INET;    
    addr.sin_addr.s_addr = inet_addr(ips);    
      
    int sockfd;    
    // 取得socket     
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);    
    if (sockfd < 0)    
    {    
        printf("ip:%s,socket errorn",ips);    
        return ERROR;    
    }    
      
    struct timeval timeo;    
    // 设定TimeOut时间     
    timeo.tv_sec = timeout / 1000;    
    timeo.tv_usec = timeout % 1000;    
      
    if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)) == -1)    
    {    
        printf("ip:%s,setsockopt errorn",ips);    
        return ERROR;    
    }    
      
    char sendpacket[PACKET_SIZE];    
    char recvpacket[PACKET_SIZE];    
    // 设定Ping包     
    memset(sendpacket, 0, sizeof(sendpacket));    
      
    pid_t pid;    
    // 取得PID,作为Ping的Sequence ID     
    pid=getpid();    
      
    struct ip *iph;    
    struct icmp *icmp;    
      
    
    icmp=(struct icmp*)sendpacket;    
    icmp->icmp_type=ICMP_ECHO;  //回显请求   
    icmp->icmp_code=0;    
    icmp->icmp_cksum=0;    
    icmp->icmp_seq=0;    
    icmp->icmp_id=pid;   
    tval= (struct timeval *)icmp->icmp_data;    
    gettimeofday(tval,NULL);    
    icmp->icmp_cksum=cal_chksum((unsigned short *)icmp,sizeof(struct icmp));  //校验   
      
    int n;    
    // 发包     
    n = sendto(sockfd, (char *)&sendpacket, sizeof(struct icmp), 0, (struct sockaddr *)&addr, sizeof(addr));    
    if (n < 1)    
    {    
        printf("ip:%s,sendto errorn",ips);    
        return ERROR;    
    }    
      
    // 接受     
    // 由于可能接受到其他Ping的应答消息,所以这里要用循环     
    while(1)    
    {    
        // 设定TimeOut时间,这次才是真正起作用的     
        FD_ZERO(&readfds);    
        FD_SET(sockfd, &readfds);    
        maxfds = sockfd + 1;    
        n = select(maxfds, &readfds, NULL, NULL, &timeo);    
        if (n <= 0)    
        {    
            printf("ip:%s,Time out errorn",ips);    
            close(sockfd);    
            return ERROR;    
        }    
          
        // 接受     
        memset(recvpacket, 0, sizeof(recvpacket));    
        int fromlen = sizeof(from);    
        n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);    
        if (n < 1) {    
            break;    
        }    
          
       
        char *from_ip = (char *)inet_ntoa(from.sin_addr);    
            // 判断是否是自己Ping的回复     
        if (strcmp(from_ip,ips) != 0)    
        {    
            printf("NowPingip:%s Fromip:%snNowPingip is not same to Fromip,so ping wrong!n",ips,from_ip);    
            return ERROR;  
        }    
          
        iph = (struct ip *)recvpacket;    
          
        icmp=(struct icmp *)(recvpacket + (iph->ip_hl<<2));    
          
        printf("ip:%sn,icmp->icmp_type:%dn,icmp->icmp_id:%dn",ips,icmp->icmp_type,icmp->icmp_id);    
        // 判断Ping回复包的状态     
        if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid)   //ICMP_ECHOREPLY回显应答   
        {    
            // 正常就退出循环     
            break;    
        }    
        else    
        {    
            // 否则继续等     
            continue;    
        }    
    }    
      
    int main()  
{  
    char cPing[16];  
    printf("Please input ping IP:");  
    scanf("%s",cPing);  
      
    if(ping(cPing,10000))  
    {  
        printf("Ping succeed!n");  
    }  
    else  
    {  
        printf("Ping wrong!n");  
    }  
      
}  
测试结果:
root@an-virtual-machine:~/wyz/test# ./testping
Please input ping IP:192.168.1.155
Nowip:192.168.1.155 Fromip:192.168.1.133
Nowip is not same to Fromip,so ping wrong!
Ping wrong!
root@an-virtual-machine:~/wyz/test# ./testping
Please input ping IP:192.168.1.188
ip:192.168.1.188
,icmp->icmp_type:0
,icmp->icmp_id:27865
Ping succeed!

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读