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

165
在Linux环境中,我需要检测RJ45连接器与其插座的物理连接或断开状态。最好只使用BASH脚本来实现。
以下解决方案在其他网站上提出,但不适用于此目的:
1.使用'ifconfig' - 因为网络电缆可能已连接,但网络未正确配置或当前未启动。 2.ping主机 - 因为该产品将位于LAN中,使用未知的网络配置和未知的主机。
在/proc文件系统中没有可以使用的状态吗(其他所有东西都在那里)?
Linux世界应该如何拥有自己的版本的Windows气泡从图标托盘弹出,表示您刚刚拔掉了网络电缆?
Kent Fredric和lothar,你们两个的回答都满足我的需要...非常感谢!我将使用哪一个...我仍然不知道。
我想我不能同时选择你们两个作为正确答案?选择一个对你们来说可能更公平。翻个硬币,我猜?再次感谢!
16个回答

261
你想查看位于 /sys/class/net/ 目录下的节点。
我对我的电脑进行了测试:
网线插入时:
eth0/carrier:1
eth0/operstate:unknown

线被移除:

eth0/carrier:0
eth0/operstate:down

插头再次插入:

eth0/carrier:1
eth0/operstate:up

小贴士:一次简单地收集所有属性的方法:

grep "" eth0/* 

这将形成一个漂亮的键:值对列表。


8
请注意,正如Marco在下面所说的,必须使接口处于启用状态(即使未配置)才能查询这些值。 - Jamie Kitson
16
使用“grep"" eth0/*”非常简洁易懂,谢谢!使用“-s”开关后,grep不会抱怨目录。 - Ray
2
我更喜欢使用命令:grep -H . eth0/*。这个命令可以去除空行并打印每行所属的条目名称。 - F. Hauri - Give Up GitHub
2
可以使用以下命令忽略grep中关于目录的错误:grep -s "" eth0/* - mrtumnus
请注意接口必须处于启动状态。请参考下面的Marco的回答。在我的系统中,eth0默认未设置,我的程序会随机生成一个IP地址。当我尝试读取载波时,会出现“无效参数”错误。 - VocoJax
显示剩余2条评论

98

你可以使用ethtool

$ 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

要仅获取链接状态,您可以使用grep:

$ sudo ethtool eth0 | grep Link
    Link detected: yes

1
ip link | grep BROADCAST |cut -d ':' -f 2 | while read i; do echo $i; ethtool $i | grep Link ; done - Bryan Hunt
3
请注意,正如Marco在下面所说的那样,要查询这些值,接口必须处于启用状态(即使未配置)。 - Jamie Kitson
这太棒了!我有一种方法可以检查以太网是否可用,是否启用以太网,以太网是否连接,但无法检查实际的电缆是否连接。grep Link 可以做到。谢谢!! - ᴛʜᴇᴘᴀᴛᴇʟ
这里无法工作。在HP硬件上安装的Ubuntu 16.04,未配置的接口显示为“无链接”,即使强制设置为“up”状态也是如此。 - 0xF2

30

使用 'ip monitor' 命令可以实时获取链接状态变化。


3
在我的情况下,这是唯一有效的答案...... 当我的电缆断开时,/sys/class/net/eth0/carrier仍显示“1”,而“ip monitor”实际上显示了一些内容。 - Tim Tisdall
关于这种方法的一些更详细的解释可以感谢 Peter。例如,任何能回答关于了解电缆插头状态的原始问题的示例。 - Sopalajo de Arrierez

18

cat /sys/class/net/ethX 是最简单的方法。

但是接口必须处于启动状态,否则你将会收到一个无效参数错误。

所以先执行:

ifconfig ethX up

那么:

cat /sys/class/net/ethX

5
请尝试输入命令"cat /sys/class/net/eth[n]/operstate",其中的[n]是指eth设备的编号。 - pmont
这只告诉你eth[n]是否启动,如果它关闭了,它不会告诉你电缆是否连接。 - Brice
@Brice,确实,您想要检查文件ethX/carrier,如果检测到“carrier”,即表示连接了电缆并传输数据,则该文件的值为1... - Alexis Wilke
这对我很有用,使用Process Runtime Exec命令来检查Android中的电缆是否连接。 - Arlyn
或者,在执行 ifconfig ethX up 命令后,执行 ifconfig ethX 命令并查看 RUNNING 状态。 - craig65535

9
在低级别上,可以使用rtnetlink套接字捕获这些事件,无需任何轮询。附带说明:如果您使用rtnetlink,则必须与udev一起工作,否则当udev重命名新的网络接口时,您的程序可能会混淆。
使用shell脚本进行网络配置的问题在于,shell脚本对于事件处理(例如插入和拔出网络电缆)非常糟糕。如果您需要更强大的功能,请看看我的NCD编程语言,这是专为网络配置而设计的编程语言。
例如,一个简单的NCD脚本将在标准输出中打印“cable in”和“cable out”(假设接口已经启动):
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地址将自动删除。

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

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

如果结果是上升或下降。有时会显示未知,那么您需要检查。

eth0/carrier

它显示0或1。

5

有两个守护进程可以检测这些事件:

ifplugdnetplugd


我使用ifplugd守护程序中的ifplugstatus工具。无需参数,只需键入ifplugstatus即可获取所有NIC的插入或拔出状态。 - Sopalajo de Arrierez

3

一些细节和技巧

  1. I do all this as normal user (not root)

  2. Grab infos from dmesg

    Using dmesg is one of the 1st things to do for inquiring current state of system:

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

    could answer something like:

    [936536.904154] e1000e: eth0 NIC Link is Down
    

    or

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

    depending on state, message could vary depending on hardware and drivers used.

    Nota: this could by written dmesg|grep eth.*Link.is|tail -n1 but I prefer using 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
    

    Could render something like (once you've unplugged and plugged back, depending ):

    +++ -   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
    

    (Hit Enter to exit loop)

    Nota: This require patch to be installed.

  4. In fine, there must already be something about this...

    Depending on Linux Installation, you could add if-up and if-down scripts to be able to react to this kind of events.

    On Debian based (like Ubuntu), you could store your scripts into

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

    see man interfaces for more infos.


感谢您对此事的评论和建议。不过,您应该意识到这些都是“自动化”的脚本。在第二点中,当您说输出“或者”另一个输出时,或者当您说“根据状态,消息可能因使用的硬件和驱动程序而有所不同”时……这是一个非常大的问题。输出必须保持一致,否则生产脚本就会出现问题。但无论如何,这是很好的信息,谢谢。 - Jeach
@Jeach 输出可能会有所不同的意思是:您可以使用除e1000以外的其他驱动程序事件可能发生在936555.596870之外的其他时间,但您始终会看到*NIC Link is*。 - F. Hauri - Give Up GitHub

3

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

如果您想要一个命令行工具来检查状态,您也可以使用mii-tool,前提是您考虑的是以太网。


3
mii-tool已被ethtool取代。mii-tool不支持GigE链接。 - JimB
此外,大多数服务器都具有手动配置的适配器,这些适配器被NM忽略。 - JimB
1
“mii-tool” 似乎是唯一一个在接口关闭时可以报告链路状态的命令。 - donothingsuccessfully

2

如果您想要在Linux系统下检查以太网电缆是否插好,可以在执行“ifconfig eth0 down”命令后使用ethtool工具。

#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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接