当前日期:2023年11月29日 星期三
Hi 你好,欢迎访问!登录
搜索 导航

凯特网-Think and Do it , as Soon as!

当前位置:首页 - 程序设计 - C++ - 正文
阅读模式

linux C 实现ping功能

2023-09-17 | C++ | caterwang | 154°c

核心代码引自:Linux C++ 实现一个简易版的ping (也就是ICMP协议)-腾讯云开发者社区-腾讯云 (tencent.com)

以下为我实际使用的代码

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h> 

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函数,timeout为超时时间,单位是ms,我实际用时默认10000
//成功:返回0,失败:返回1或-1
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  。  如果没加sudo 这里会报错
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);  
    if (sockfd < 0)  
    {  
        printf("ip:%s,socket error\n",ips);  
        return -1;  
    }  
    
    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 error\n",ips); 
		close(sockfd);
        return -1;  
    }  
 
    char sendpacket[2048];  
    char recvpacket[2048];  
    // 设定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 = sendto(sockfd, (char *)&sendpacket, sizeof(struct icmp), 0, (struct sockaddr *)&addr, sizeof(addr));  
    if (n < 1)  
    {  
        printf("ip:%s,sendto error\n",ips); 
		close(sockfd);
        return -1;  
    }  
    
    // 接受  
    // 由于可能接受到其他Ping的应答消息,所以这里要用循环
    int cnt=0;
    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 error\n",ips);  
            close(sockfd);  
            return -1;  
        }  
        
        // 接受  
        memset(recvpacket, 0, sizeof(recvpacket));  
        int fromlen = sizeof(from);  
        n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen);  
    	printf("recvfrom Len:%d\n",n);
        if (n < 1) 
    	{  
    		close(sockfd);
        	return 1;  
        }          
     
        char *from_ip = (char *)inet_ntoa(from.sin_addr);  
        // 判断是否是自己Ping的回复  
        if (strcmp(from_ip,ips) != 0)  
        {  
           printf("NowPingip:%s Fromip:%s NowPingip is not same to Fromip,so ping wrong!\n",ips,from_ip);  
		   close(sockfd);
           return 1;
        }  
        
        iph = (struct ip *)recvpacket;  
        
        icmp=(struct icmp *)(recvpacket + (iph->ip_hl<<2));  
        
        printf("ip:%s,icmp->icmp_type:%d,icmp->icmp_id:%d\n",ips,icmp->icmp_type,icmp->icmp_id);  
        // 判断Ping回复包的状态  
        if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid)   //ICMP_ECHOREPLY回显应答
        {  
            // 正常就退出循环 
        	printf("icmp succecss .............  \n");
            break;  
        }  
        else if(cnt<3) 
        {  
            // 否则继续等
            cnt++;
            continue;  
        }
	else
	{
	    close(sockfd);
	    return -1;
	}
    } 
	close(sockfd);
    return 0;
}


请使用支付宝赞助我

支付宝打赏

请使用微信赞助我

微信打赏

版权声明

欢迎转载,但注明出处,谢谢!

分享:
0
QR:  linux C 实现ping功能

扫一扫,用手机打开吧

TAGS:

推荐文章

共0条评论

暂时没有评论,你可以来抢个沙发!

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

展开