以太网通信拔掉网线的几种判别方法——问题由来拔掉网线后由于发送函数一直存在导致无法使用套接字的保活功能判别套接字是否为连接状态
拔掉网线后SSCOM模拟服务器会自动断开,插上网线后客户端会提示错误
方法1 :
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #define SERVER_PORT 8899 void setkeepalive(int socket) { int keep_alive = 1; // 开启保活功能 int KEEP_ALIVE_TIME = 30; // 60秒发送一次Keep-alive包 int KEEP_ALIVE_INTVL = 2; // 每10秒重试一次 int KEEP_ALIVE_PROBES = 2; // 如果5次探测都没有响应,则认为连接断开 // 设置TCP_USER_TIMEOUT选项 if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive)) < 0) { perror("Error setting keep alive fialed"); } /*int timeout = 30000; // 设置超时时间为30秒 if (setsockopt(sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout)) < 0) { perror("Error setting user timeout"); return 1; }*/ // 设置TCP Keep-alive参数 // 设置TCP_KEEPIDLE选项,值为5秒,代表如果TCP连接上有五秒钟没有任何数据包传输,则启动保活机制,发送TCP Keep-alive机制。默认为2小时 if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &KEEP_ALIVE_TIME, sizeof(KEEP_ALIVE_TIME)) < 0) { perror("Error setting keep alive time"); } // 设置TCP_KEEPINTVL选项,值为1秒,代表如果启动保活机制,则每隔1秒发送一个Keep-alive包。默认为75秒。汇川默认5秒一包 if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &KEEP_ALIVE_INTVL, sizeof(KEEP_ALIVE_INTVL)) < 0) { perror("Error setting keep alive interval"); } // 设置TCP_KEEPCNT选项,值为3,代表如果对端对3次Keep-alive数据包都没有正常响应,则判断对端已经崩溃。默认为9。 if (setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &KEEP_ALIVE_PROBES, sizeof(KEEP_ALIVE_PROBES)) < 0) { perror("Error setting keep alive probes"); } } int main() { int clientSocket; struct sockaddr_in serverAddr; char sendbuf[2] ={1,1}; char recvbuf[200]; int iDataNum; struct tcp_info info; int len = sizeof(info); if ((clientSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1; } serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(SERVER_PORT); serverAddr.sin_addr.s_addr = inet_addr("192.168.1.33"); // 设置保活选项 int keepAlive = 1; // 开启Keep-Alive属性 int keepIdle = 60; // 在认定连接空闲之前等待的时间(秒) int keepInterval = 5; // 尝试发送keepalive探测包的间隔时间(秒) int keepCount = 3; // 最多尝试发送探测包的次数 // 开启保活选项 if(setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive)) < 0) { perror("setsockopt failed: SO_KEEPALIVE"); close(clientSocket); exit(EXIT_FAILURE); } // 设置空闲时间 if(setsockopt(clientSocket, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(keepIdle)) < 0) { perror("setsockopt failed: TCP_KEEPIDLE"); close(clientSocket); exit(EXIT_FAILURE); } // 设置探测包发送间隔 if(setsockopt(clientSocket, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(keepInterval)) < 0) { perror("setsockopt failed: TCP_KEEPINTVL"); close(clientSocket); exit(EXIT_FAILURE); } // 设置探测次数 if(setsockopt(clientSocket, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(keepCount)) < 0) { perror("setsockopt failed: TCP_KEEPCNT"); close(clientSocket); exit(EXIT_FAILURE); } if (connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { perror("connect"); return 1; } int i; while (1) { memset(&info,0,sizeof(struct tcp_info)); getsockopt(clientSocket, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len); printf("i=%d info.tcpi_state =%d\n",i,info.tcpi_state); //send(clientSocket, sendbuf, strlen(sendbuf), 0);——调用该函数时无法正确反馈断线状态 sleep(1); i++; } close(clientSocket); return 0; }
使用保活机制,有弊端,如果该套接字被调用发送函数和接收函数该套接字的状态仍为info.tcpi_state =1,如果没有上述发送接收函数则返回info.tcpi_state =7
保活机制不能和发送接收函数一起用!!!
方法2:
1、使用ethtool命令
ethtool是一个强大的网络接口配置和诊断工具。你可以使用它来查询指定网络接口的状态。
首先,确保你的系统已安装ethtool。如果没有,请使用包管理器进行安装。例如,在基于Debian的系统上,可以使用sudo apt-get install ethtool。
使用以下命令检查特定网络接口(如eth0)的状态:
sudo ethtool eth0
xxxx# ethtool eth0 Settings for eth0: Supported ports: [ TP MII ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full Supported pause frame use: Symmetric Receive-only Supports auto-negotiation: Yes Supported FEC modes: Not reported Advertised link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full Advertised pause frame use: Symmetric Receive-only Advertised auto-negotiation: Yes Advertised FEC modes: Not reported Speed: 100Mb/s Duplex: Full Auto-negotiation: on Port: Twisted Pair PHYAD: 1 Transceiver: internal MDI-X: Unknown Supports Wake-on: ug Wake-on: d Current message level: 0x0000003f (63) drv probe link timer ifdown ifup Link detected: yes
在输出的信息中查找Link detected字段,如果是yes表示物理连接正常;如果是no则表示网线可能已被拔掉。
2、使用ip命令
ip命令也是一个非常有用的网络配置工具,可用于查看网络接口状态。
运行如下命令查看所有网络接口的状态:
ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether e4:73:05:02:f8:97 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000 link/ether e4:73:05:02:f8:98 brd ff:ff:ff:ff:ff:ff
查找你想检查的网络接口名称(例如eth0),如果显示state UP并且有类似link/ether这样的信息,则表明网线已正确连接。如果显示state DOWN或者缺少这些信息,可能意味着网线未连接。
3、读取/sys/class/net/下的文件
Linux系统将每个网络接口的信息暴露在/sys/class/net/目录下对应的子目录中。你可以直接读取这些文件来获取状态。
对于接口eth0,你可以使用以下命令来检查其携带状态:
cat /sys/class/net/eth0/carrier root@xxx00:~/work/ts300# cat /sys/class/net/eth0/carrier 1 root@xx00:~/work/ts300# cat /sys/class/net/eth0/carrier 0 root@xx00:~/work/ts300# cat /sys/class/net/eth0/carrier 0 root@xx00:~/work/ts300# cat /sys/class/net/eth0/carrier 1
如果输出为1,则表示物理连接存在;如果输出为0,则表示没有检测到连接(即网线可能被拔出)。
浙公网安备 33010602011771号