zoukankan      html  css  js  c++  java
  • 网络异常检测

    网络异常检查

    2

    文章分类 : C语言LinuxWindows应用与编程网络

    一、本文目的

    在涉及网络编程的实际项目应用中,由于网络不可能一直处于理想状态,TCP长连接也可能随时正常或异常地断开,如果不予处理,那么就可能因此而给程序带来很多潜在的问题。 编写该文档的目的就在于针对网络程序中可能遇到的各种问题,拿出来与大家探讨一下具体问题的解决方案,同时本人将前期调研的一些解决方案列出来,抛砖引玉,希望可以集思广益,寻求到更加合理的解决方案。    

    二、网络断开时机

    1、正常网络断开

    (1) CS 一方调用 Close

    (2) CS 一方程序正常退出,如Ctrl + C 事件可以被系统检测到,对应的套接字也将被系统标记为已断开。

    2、异常网络断开

    (1) CS 一方网线被拨出

    (2) CS 之间路由故障,物理连接断开

    (3) CS 一方断电或当机

    (4) CS 一方无线信号不佳或无线接口被关闭

    (5) CS 一方更改 IP 事件无法被系统检测到,这个时候读数据不会出错,只会一直阻塞着;写数据在缓冲区未满之前也不会返回错误。若无法及时检测到断开事件,对某些应用场景而言可能存在致命的错误。如服务端维护的客户端在线信息错误等。

    三、网络断开常用检测方法

    1、处理正常网络断开

    (1) select 捕捉可读事件,read返回0

    (2) epoll 捕捉可读事件,read返回0

    (3) 主动 read 返回错误

    (4) 主动 write 返回错误

    2、处理异常网络断开

    (1) 应用层KeepAlive检测

    在应用层协议加入心跳握手机制,维护服务端跟客户端之间的连通状态,是最普遍最保险的办法。 客户端定时向服务端发送探测包,若服务端回应则说明服务端在线,否则作离线处理;服务端也可对长期未发送探测包的客户端作离线处理。 该方案所有系统都支持,跨平台性好;对端跟自身出现网络故障都能检测到。不足之处在于它需要应用层协议支持,程序内部需要长期维护心跳握手包,相对比较繁琐。

    (2) 传输层KeepAlive检测

    除了应用层 KeepAlive 检测机制外,TCP 内部也集成了 KeepAlive 机制,默认关闭,开启它很方便。对端跟自身出现网络故障都能检测到。但不是所有的系统都支持,而且有些系统虽然支持但会影响到所有套接字,消耗额外的宽带和流量,不建议使用。

    1. //启用心跳机制,如果您想关闭,将keepAlive置零即可  
    2. setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive));  
    3. //启用心跳机制开始到首次心跳侦测包发送之间的空闲时间  
    4. setsockopt(fd,SOL_TCP,TCP_KEEPIDLE,(void *)&start,sizeof(start));  
    5. //两次心跳侦测包之间的间隔时间  
    6. setsockopt(fd,SOL_TCP,TCP_KEEPINTVL,(void *)&interval,sizeof(interval));  
    7. //探测次数,即将几次探测失败判定为TCP断开  
    8. setsockopt(fd,SOL_TCP,TCP_KEEPCNT,(void *)&count,sizeof(count));  

    (3) 网络层KeepAlive检测

    Ping 命令几乎是所有平台的网络连通性检测命令,走网络层 ICMP 协议,这里考虑使用 popen 函数调用系统自带的 Ping 命令来封装网络连通性检测函数。它实际上也是一种网络层的 KeepAlive 机制。

    1. int checkConnect(char *dst, int cnt)  
    2. {  
    3.     FILE *stream;  
    4.     sprintf(cmdBuf, "ping %s -c %d -i 0.2 | grep time= | wc -l", dst, cnt);  
    5.     stream = popen(cmdBuf, "r");  
    6.     fread(recvBuf, sizeof(char), sizeof(recvBuf)-1, stream);  
    7.     pclose(stream);  
    8.     if (atoi(recvBuf) > 0) return 0;  
    9.     return -1;  
    10. }  

    dst 指定要检测的目的地址,cnt 指定 Ping 尝试的次数,-i 参数指定 Ping 尝试的超时时间。

    (4) 应用层监控内核消息机制

    Netlink 是一种特殊的套接字,为2.6.14及更高版本的Linux所特有,通过它,应用层程序可以方便地向内核订制指定消息,如网卡上下线。也可以设置或查询配置,如IP、路由、网络流量信息等。

    a、创建一个 netlink 套接字:

    1. fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);  

    b、绑定路由多播组,监控网卡信息:

    1. addr.nl_family = AF_NETLINK;  
    2. addr.nl_groups = RTNLGRP_LINK; //指定接收路由多播组消息  
    3. bind(fd, (struct sockaddr*)&addr, sizeof(addr));  

    c、监听套接字,一旦可读,解析其内容,实时监控网卡上下线事件。

    优点:实时性高,使用方便。

    缺点:跨平台性不佳,只能检测自身网络故障。

    (5) 应用层网卡信息轮询机制

    网卡信息轮询机制就是定期调用 ioctl 函数执行如下操作:

    1. struct ifconf ifc;  
    2. struct ifreq ifrcopy;  
    3. //获取网卡信息列表  
    4. ioctl(fd, SIOCGIFCONF, (char *)&ifc);  
    5. //获取网卡上下线状态  
    6. ioctl(fd, SIOCGIFFLAGS, &ifrcopy);  
    7. //获取 MAC 地址  
    8. ioctl(fd, SIOCGIFHWADDR, (char *)(&ifrcopy);  
    9. //获取 IP 地址  
    10. ioctl(fd, SIOCGIFADDR, (char *)&ifrcopy);  
    11. //获取广播地址  
    12. ioctl(fd, SIOCGIFBRDADDR, &ifrcopy));  

    缺点:

    a、跨平台性不佳。

    可以成功移植到 Linux、AndroidWindows平台,但由于 iPhone 平台上获取MAC跟IP的参数不同,需特殊处理。

    b、实时性跟灵活性不高。

    c、耗费资源,影响性能。

    d、只能检测自身网络故障。

  • 相关阅读:
    Spring3.0 AOP 具体解释
    bcompare3+keygen
    解决git每次输入密码,设置gitlab、github默认push的用户名和密码
    15款免费WiFi入侵破解安全测试工具
    六款主流免费网络嗅探软件wireshark,tcpdump,dsniff,Ettercap,NetStumbler
    wan口mac=lan口mac加一,wlan是lan口mac加二
    MOUNT MACBOOK DISK (OSX / HFS+) ON UBUNTU 12.04 LTS WITH READ/WRITE
    /sbin/ifup: configuration for eth0 not found解决
    delete
    vbox安装mac os x
  • 原文地址:https://www.cnblogs.com/huyayuan1/p/4949190.html
Copyright © 2011-2022 走看看