如何检测网络电缆/连接器的物理连接状态?

在 Linux 环境中,我需要检测连接到其套接字的 RJ45连接器的物理连接或断开连接状态。最好只使用 BASH 脚本。

在其他网站上提出的下列解决方案不适用于此目的:

  1. 使用“ ifconfig”-因为网络电缆可能被连接,但网络没有正确配置或当前没有上线。
  2. Ping 一个主机-因为产品将在一个局域网内使用未知的网络配置和未知的主机。

在/proc 文件系统中是否有一些可以使用的状态(其他所有内容都在其中) ?

Linux 世界怎么会有自己版本的 Windows 泡泡,它从图标托盘中弹出,表示您刚刚拔掉了网络电缆?


肯特 · 弗雷德里克和 Lothar,你们的答案都满足了我的需要... ... 非常感谢!我会用哪个... 我还不知道。

我想我不能把你们两个都算作正确答案吧?也许我选一个对你来说是公平的。我猜是抛硬币吧?再说一遍,谢谢!

349522 次浏览

大多数现代 Linux 发行版都使用 网络管理器进行此操作,您可以使用 D-BUS 来监听事件。

如果希望使用命令行工具检查状态,还可以使用 mii-tool,因为您考虑的是以太网。

你可以使用 乙工具:

$ sudo ethtool eth0
Settings for eth0:
Supported ports: [ TP ]
Supported link modes:   10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supports auto-negotiation: Yes
Advertised link modes:  10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
Auto-negotiation: on
Supports Wake-on: umbg
Wake-on: g
Current message level: 0x00000007 (7)
Link detected: yes

要想只获得 Link 状态,可以使用 grep:

$ sudo ethtool eth0 | grep Link
Link detected: yes

中的节点

/sys/class/net/

我尝试了我的方法:

电线插头:

eth0/carrier:1
eth0/operstate:unknown

拆除电线:

eth0/carrier:0
eth0/operstate:down

电线再次插入:

eth0/carrier:1
eth0/operstate:up

附带技巧: 以简单的方式一次性获得所有财产:

grep "" eth0/*

这形成了一个不错的 key:value对列表。

cat /sys/class/net/ethX是目前为止最简单的方法。

接口必须打开,否则你会得到一个无效的参数错误。

首先:

ifconfig ethX up

然后:

cat /sys/class/net/ethX

在底层,可以使用 Rtnetlink套接字捕获这些事件,而不需要任何轮询。附注: 如果您使用 rtnetlink,则必须与 udev 一起工作,否则当 udev 重命名新的网络接口时,您的程序可能会混淆。

使用 shell 脚本进行网络配置的问题在于 Shell 脚本对于事件处理非常糟糕(例如正在插入和拔出的网络电缆)。如果您需要更强大的东西,看看我的 NCD 编程语言,一种为网络配置设计的编程语言。

例如,一个简单的 NCD 脚本将打印“连接到”和“连接到”标准输出(假设接口已经打开) :

process foo {
# Wait for device to appear and be configured by udev.
net.backend.waitdevice("eth0");
# Wait for cable to be plugged in.
net.backend.waitlink("eth0");
# Print "cable in" when we reach this point, and "cable out"
# when we regress.
println("cable in");   # or pop_bubble("Network cable in.");
rprintln("cable out"); # or rpop_bubble("Network cable out!");
# just joking, there's no pop_bubble() in NCD yet :)
}

(在内部,net.backend.waitlink()使用 rtnetlink,而 net.backend.waitdevice()使用 udev)

NCD 的思想是,您只能使用它来配置网络,因此通常情况下,配置命令会介于两者之间,例如:

process foo {
# Wait for device to appear and be configured by udev.
net.backend.waitdevice("eth0");
# Set device up.
net.up("eth0");
# Wait for cable to be plugged in.
net.backend.waitlink("eth0");
# Add IP address to device.
net.ipv4.addr("eth0", "192.168.1.61", "24");
}

需要注意的重要部分是允许对 倒退执行; 例如,在第二个示例中,如果拔出电缆,IP 地址将被自动删除。

使用“ ip 监视器”获得实时链接状态的变化。

存在两个检测这些事件的守护进程:

Ifplugd 和 < strong > netplugd

我使用这个命令来检查电线是否连接:

cd /sys/class/net/
grep "" eth0/operstate

如果结果将上升或下降。有时它显示未知,那么你需要检查

eth0/carrier

它显示0或1

一些精确度和技巧

  1. 我所做的这一切作为 正常使用者(而不是 )

  2. dmesg获取信息

    使用 dmesg是查询系统 现状要做的第一件事:

    dmesg | sed '/eth.*Link is/h;${x;p};d'
    

    可以回答这样的问题:

    [936536.904154] e1000e: eth0 NIC Link is Down
    

    或者

    [936555.596870] e1000e: eth0 NIC Link is Up 100 Mbps Full Duplex, Flow Control: Rx/Tx
    

    根据状态的不同,消息可能会因所使用的硬件和驱动程序而不同。

    注意: 这可以由书面 dmesg|grep eth.*Link.is|tail -n1,但我更喜欢使用 sed

    dmesg | sed '/eth.*Link is/h;${x;s/^.*Link is //;p};d'
    Up 100 Mbps Full Duplex, Flow Control: Rx/Tx
    
    
    dmesg | sed '/eth.*Link is/h;${x;s/^.*Link is //;p};d'
    Down
    
  3. Test around /sys pseudo filesystem

    Reading or writting under /syscould break your system, especially if run as root! You've been warned ;-)

    This is a pooling method, not a real event tracking.

    cd /tmp
    grep -H . /sys/class/net/eth0/* 2>/dev/null >ethstate
    while ! read -t 1;do
    grep -H . /sys/class/net/eth0/* 2>/dev/null |
    diff -u ethstate - |
    tee >(patch -p0) |
    grep ^+
    done
    

    可以呈现如下内容(一旦你拔掉插头并重新插上,取决于) :

    +++ -   2016-11-18 14:18:29.577094838 +0100
    +/sys/class/net/eth0/carrier:0
    +/sys/class/net/eth0/carrier_changes:9
    +/sys/class/net/eth0/duplex:unknown
    +/sys/class/net/eth0/operstate:down
    +/sys/class/net/eth0/speed:-1
    +++ -   2016-11-18 14:18:48.771581903 +0100
    +/sys/class/net/eth0/carrier:1
    +/sys/class/net/eth0/carrier_changes:10
    +/sys/class/net/eth0/duplex:full
    +/sys/class/net/eth0/operstate:up
    +/sys/class/net/eth0/speed:100
    

    (按 Enter退出循环)

    注意: 这需要安装 patch

  4. 总而言之,这件事肯定已经有些蹊跷了。

    根据 Linux 安装,您可以添加 if-upif-down脚本,以便能够对此类事件作出反应。

    基于 Debian(如 Ubuntu) ,您可以将脚本存储到

    /etc/network/if-down.d
    /etc/network/if-post-down.d
    /etc/network/if-pre-up.d
    /etc/network/if-up.d
    

    更多信息见 man interfaces

在 arch linux 上。(我不确定在其他发行版)你可以查看操作状态。如果操作状态不存在,则显示为连接状态或关闭状态

/sys/class/net/(interface name here)/operstate
#you can also put watch
watch -d -n -1 /sys/class/net/(interface name here)/operstate

可以使用 ifconfig。

# ifconfig eth0 up
# ifconfig eth0

如果条目显示为 RUNWN,则接口是物理连接的。无论接口是否配置,都会显示这一点。

这只是在 /sys/class/net/eth0/operstate中获取信息的另一种方法。

我使用我的 OpenWRT 增强设备作为中继器(它增加了虚拟以太网和无线局域网功能) ,发现/sys/class/net/eth0运营商和 opstate 值是不可靠的。我也试过/sys/class/net/eth0.1和/sys/class/net/eth0.2(至少在我看来) ,没有可靠的方法来检测是否有什么东西物理地插入了以太网端口,或者在任何以太网端口上通话。我找到了一个有点粗糙但看起来可靠的方法来检测是否有什么东西至少在最后一次重启/启动状态之后就已经插上了(在我的案例中,这种方法正是我所需要的)。

ifconfig eth0 | grep -o 'RX packets:[0-9]*' | grep -o '[0-9]*'

如果从上次开机或重启周期开始,没有插入任何东西,那么得到的结果是0; 如果有任何东西已经插入(即使已经插入并且已经删除) ,那么得到的结果是 > 0。

希望这至少能帮到别人!

tail -f /var/log/syslog | grep -E 'link (up|down)'

或者对我来说更快得到:

tail -f /var/log/syslog | grep 'link \(up\|down\)'

它将侦听 syslog 文件。

结果(如果断开连接并在4秒后再次连接) :

Jan 31 13:21:09 user kernel: [19343.897157] r8169 0000:06:00.0 enp6s0: link down
Jan 31 13:21:13 user kernel: [19347.143506] r8169 0000:06:00.0 enp6s0: link up

以某种方式,如果你想检查是否以太网电缆插入 linux 后的推荐: “ ifconfig eth0下来”。 我找到了解决办法: 用这个工具。

#ethtool -t eth0
The test result is PASS
The test extra info:
Register test  (offline)         0
Eeprom test    (offline)         0
Interrupt test (offline)         0
Loopback test  (offline)         0
Link test   (on/offline)         0

如果连接了电缆,连接测试为0,否则为1。

在 OpenWRT 上,至少对我来说,唯一可靠的方法就是运行以下命令:

# Get switch name
swconfig list


# assuming switch name is "switch0"
swconfig dev switch0 show | grep link:


# Possible output
root@OpenWrt:~# swconfig dev switch0 show | grep link:
link: port:0 link:up speed:1000baseT full-duplex txflow rxflow
link: port:1 link:up speed:1000baseT full-duplex txflow rxflow eee100 eee1000 auto
link: port:2 link:up speed:1000baseT full-duplex txflow rxflow eee100 eee1000 auto
link: port:3 link:down
link: port:4 link:up speed:1000baseT full-duplex eee100 eee1000 auto
link: port:5 link:down
link: port:6 link:up speed:1000baseT full-duplex txflow rxflow

这将在交换机的每个端口上显示“ link: down”或“ link: up”。

该命令在“ ip a”命令的第2个接口中检查“ state UP”。我已经检查了2台运行无线网络的电脑,第二台是有线以太网。如果你想检查一个不同的界面,只需要改变下面命令中的“2”为正确的索引位置。

astate=`ip a | grep -E -o -m 1 "2:.*state UP"`
if [ -n "$astat" ]; then
echo 'cable is on'
else
echo 'cable is off'
fi