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

Linux检测网络故障以及恢复网络的技巧

发布时间:2021-11-25 19:19:21 所属栏目:教程 来源:互联网
导读:在项目中遇到一个问题,嵌入式Linux设备工作一段时间后网络会出现故障,网线虽然连着,但却不能与外部主机通信。此时用串口调试内核,用ifconfig eth0 up命令可以再度启动网络。所以现在的需要在网络故障时检测出来,然后复位网络。 如何检测网络故障是一个

在项目中遇到一个问题,嵌入式Linux设备工作一段时间后网络会出现故障,网线虽然连着,但却不能与外部主机通信。此时用串口调试内核,用ifconfig eth0 up命令可以再度启动网络。所以现在的需要在网络故障时检测出来,然后复位网络。
 
如何检测网络故障是一个问题,在网上搜索了半天也没有找到好的解决方法。突然想到可以自己实现linux中的ping命令,然后定时ping网关,依据是否能ping通网关就可以判断出网络是否故障。
 
 
然后把这个程序嵌入我的程序中,实现了功能。下面是ping函数部分的代码:
 
//自定义ping函数参数   
#define PACKET_SIZE                         4096   
#define ERROR                               0   
#define SUCCESS                             1   
#define PING_TIME                           10000                               //10S   
#define PING_TIME_OUT                       1000                                //1S
// 效验算法   
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 timeo;  
    int sockfd;  
    struct sockaddr_in addr;  
    struct sockaddr_in from;  
  
    struct timeval *tval;  
    struct ip *iph;  
    struct icmp *icmp;  
  
    char sendpacket[PACKET_SIZE];  
    char recvpacket[PACKET_SIZE];  
  
    int n;  
    pid_t pid;  
    int maxfds = 0;  
    fd_set readfds;  
  
    // 设定Ip信息   
    bzero(&addr,sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_addr.s_addr = inet_addr(ips);  
  
    // 取得socket   
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);  
    if (sockfd < 0)  
    {  
        printf("ip:%s,socket error",ips);  
        return ERROR;  
    }  
  
    // 设定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",ips);  
        return ERROR;  
    }  
  
    // 设定Ping包   
    memset(sendpacket, 0, sizeof(sendpacket));  
  
    // 取得PID,作为Ping的Sequence ID   
    pid=getpid();  
    int i,packsize;  
    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;  
    packsize=8+56;  
    tval= (struct timeval *)icmp->icmp_data;  
    gettimeofday(tval,NULL);  
    icmp->icmp_cksum=cal_chksum((unsigned short *)icmp,packsize);  
  
    // 发包   
    n = sendto(sockfd, (char *)&sendpacket, packsize, 0, (struct sockaddr *)&addr, sizeof(addr));  
    if (n < 1)  
    {  
        printf("ip:%s,sendto error",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 error",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;  
        }  
  
        // 判断是否是自己Ping的回复   
        char *from_ip = (char *)inet_ntoa(from.sin_addr);  
        printf("fomr ip:%s",from_ip);  
         if (strcmp(from_ip,ips) != 0)  
         {  
            printf("ip:%s,Ip wang",ips);  
            break;  
         }  
  
        iph = (struct ip *)recvpacket;  
  
        icmp=(struct icmp *)(recvpacket + (iph->ip_hl<<2));  
  
        printf("ip:%s,icmp->icmp_type:%d,icmp->icmp_id:%d",ips,icmp->icmp_type,icmp->icmp_id);  
       // 判断Ping回复包的状态   
        if (icmp->icmp_type == ICMP_ECHOREPLY && icmp->icmp_id == pid)  
        {  
            // 正常就退出循环   
            break;  
        }  
        else  
        {  
            // 否则继续等   
            continue;  
        }  
    }  
  
    // 关闭socket   
    close(sockfd);  
  
    printf("ip:%s,Success",ips);  
    return SUCCESS;  
}
以上是ping函数的实现。然后我开了个定时器每隔10S启动一次,一旦检测到网络故障则自动恢复:
 
//ping定时器槽函数   
void alarmInterface::slot_ping_timer()  
{  
    //查看网络是否正常,否则重启网络   
    if (ping(Gate_Way_Ip.data(),PING_TIME_OUT))  
    {  
        //cout << "wang luo zheng chang" << endl;   
    }  
    else  
    {  
        //cout << "wang luo gu zhang!!!!!!!!!!!!" << endl;   
        system("ifconfig eth0 down");  
        sleep(2);  
        system("ifconfig eth0 up");  
    }  
}  
工作完成。

(编辑:东莞站长网)

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

    热点阅读