首页 > 解决方案 > 用于测试 tcp 服务器是否正在发送数据的 Shell 脚本

问题描述

我有以下问题:有一个 tcp 服务器正在发送传感器数据,我需要知道服务器是否仍在传输数据,或者服务器后面的传感器是否已停止,这需要一些操作。tcp 服务器既可以在远程机器上,也可以在本地机器上。

我的第一个想法是编写一个小 shell 程序,它通过 netcat 打开与服务器的连接,读取行,当它停止读取行时它会响铃。基本上是这样的:

#!/bin/bash
set -uo pipefail

retry_counter=0

nc 127.0.0.1 10001 | \
while true; do
  read -rt 1 input
  if [[ -n $input ]]; then
    retry_counter=0
    continue
  fi
  sleep 5
  retry_counter=$(( retry_counter+1 ))
  if [[ $retry_counter -ge 5 ]]; then
     echo "ALARM!"
     break
  fi
done 

我现在的问题是:这段代码在从 shell 的命令行启动的脚本中运行良好,但是一旦我将它打包到 systemd 服务中或从另一个脚本启动它,nc建立连接后立即关闭并且脚本总是会发出警报。

我在 ubuntu 18.04LTS 上运行

我究竟做错了什么?

编辑:

在过去的几天里,我做了一些挖掘,为自己创建了一个传感器到 tcp 网关的模拟器,并在意识到我实际上不需要整个读取线逻辑后简化了我的脚本:

watchdog_tmp.sh:

#!/bin/bash
set -u

retry_counter=0
reader=""

echo "Starting"
while [[ $retry_counter -le 5 ]]; do
  reader="$(ncat -vvv -i 10 127.0.0.1 10001 2>&1 > /dev/null | tee >(cat >&2) )"
  if [[ "$reader" =~ "Connected" ]]; then
    echo "First failure after success resetting counter"
    retry_counter=0
  else
    (( retry_counter++ ))
  fi
  echo "($retry_counter) ALARM!"
  sleep 5
done

但是问题并没有改变,如果我从 shell 的命令行运行我的 watch_dog(当传感器运行时),我会得到以下输出:

Starting
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT SUCCESS for EID 8 [127.0.0.1:10001]
Ncat: Connected to 127.0.0.1:10001.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #2)
libnsock nsock_read(): Read request from IOD #1 [127.0.0.1:10001] (timeout: -1ms) EID 18
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #2 [peer unspecified] EID 26
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 36
libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 18 [127.0.0.1:10001] (2200 bytes)
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 42
libnsock nsock_event_cancel(): Event #36 (type TIMER) cancelled
libnsock nevent_delete(): nevent_delete on event #36 (type TIMER)
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 52
libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 42 [127.0.0.1:10001] (43 bytes): $KRPHT,41.8800000,9.9003000,17.0000000*57..
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 58
libnsock nsock_event_cancel(): Event #52 (type TIMER) cancelled
libnsock nevent_delete(): nevent_delete on event #52 (type TIMER)
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 68
libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 58 [127.0.0.1:10001] (57 bytes): 0.000000   M/SEC   9.876518    DBAR    0.0 C   0.0 MS/CM.
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 74
libnsock nsock_event_cancel(): Event #68 (type TIMER) cancelled
libnsock nevent_delete(): nevent_delete on event #68 (type TIMER)
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 84
(...)
libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 234 [127.0.0.1:10001] (43 bytes): $KRPHT,41.8800000,9.9003000,17.0000000*57..
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 250
libnsock nsock_event_cancel(): Event #244 (type TIMER) cancelled
libnsock nevent_delete(): nevent_delete on event #244 (type TIMER)
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 260
libnsock nsock_trace_handler_callback(): Callback: READ EOF for EID 250 [127.0.0.1:10001]
libnsock nsock_trace_handler_callback(): Callback: TIMER SUCCESS for EID 260
Ncat: Idle timeout expired (10000 ms).
First failure after success resetting counter
(0) ALARM!
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT ERROR [Connection refused (111)] for EID 8 [127.0.0.1:10001]
Ncat: Connection refused.
(1) ALARM!
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT ERROR [Connection refused (111)] for EID 8 [127.0.0.1:10001]
Ncat: Connection refused.
(2) ALARM!
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT SUCCESS for EID 8 [127.0.0.1:10001]
Ncat: Connected to 127.0.0.1:10001.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #2)
libnsock nsock_read(): Read request from IOD #1 [127.0.0.1:10001] (timeout: -1ms) EID 18
libnsock nsock_readbytes(): Read request for 0 bytes from IOD #2 [peer unspecified] EID 26
libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 36
(...)
Ncat: Idle timeout expired (10000 ms).
First failure after success resetting counter
(0) ALARM!
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT ERROR [Connection refused (111)] for EID 8 [127.0.0.1:10001]
Ncat: Connection refused.
(1) ALARM!
Ncat: Version 7.01 ( https://nmap.org/ncat )
NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
libnsock nsock_trace_handler_callback(): Callback: CONNECT ERROR [Connection refused (111)] for EID 8 [127.0.0.1:10001]
Ncat: Connection refused.
(2) ALARM!

因此,我使用以下文件切换回 systemd servis:

[Unit]
Description=Watchdog for the Artemis Proxy Service
After=network.target

[Service]
ExecStart=/tmp/artemis_proxy/bin/watchdog_tmp.sh
User=kraken
Group=kraken
KillMode=process
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=default.target

它不起作用,连接在打开后立即关闭。以下是期刊的输出:

Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: Starting
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Version 7.01 ( https://nmap.org/ncat )
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: CONNECT SUCCESS for EID 8 [127.0.0.1:10001]
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Connected to 127.0.0.1:10001.
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_iod_new2(): nsock_iod_new (IOD #2)
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_read(): Read request from IOD #1 [127.0.0.1:10001] (timeout: -1ms) EID 18
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_readbytes(): Read request for 0 bytes from IOD #2 [peer unspecified] EID 26
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 36
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ EOF for EID 26 [peer unspecified]
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 18 [127.0.0.1:10001] (600 bytes)
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 42
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_event_cancel(): Event #36 (type TIMER) cancelled
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nevent_delete(): nevent_delete on event #36 (type TIMER)
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 52
Jul 29 21:31:25 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ EOF for EID 42 [127.0.0.1:10001]
Jul 29 21:31:35 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: TIMER SUCCESS for EID 52
Jul 29 21:31:35 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Idle timeout expired (10000 ms).
Jul 29 21:31:35 kraken-zbox1 watchdog_tmp.sh[31551]: First failure after success resetting counter
Jul 29 21:31:35 kraken-zbox1 watchdog_tmp.sh[31551]: (0) ALARM!
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Version 7.01 ( https://nmap.org/ncat )
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: NCAT DEBUG: Using system default trusted CA certificates and those in /etc/ssl/certs/ca-certificates.crt.
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_iod_new2(): nsock_iod_new (IOD #1)
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_connect_tcp(): TCP connection requested to 127.0.0.1:10001 (IOD #1) EID 8
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: CONNECT SUCCESS for EID 8 [127.0.0.1:10001]
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Connected to 127.0.0.1:10001.
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_iod_new2(): nsock_iod_new (IOD #2)
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_read(): Read request from IOD #1 [127.0.0.1:10001] (timeout: -1ms) EID 18
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_readbytes(): Read request for 0 bytes from IOD #2 [peer unspecified] EID 26
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 36
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ EOF for EID 26 [peer unspecified]
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ SUCCESS for EID 18 [127.0.0.1:10001] (743 bytes)
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_readbytes(): Read request for 0 bytes from IOD #1 [127.0.0.1:10001] EID 42
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_event_cancel(): Event #36 (type TIMER) cancelled
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nevent_delete(): nevent_delete on event #36 (type TIMER)
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_timer_create(): Timer created - 10000ms from now.  EID 52
Jul 29 21:31:40 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: READ EOF for EID 42 [127.0.0.1:10001]
Jul 29 21:31:50 kraken-zbox1 watchdog_tmp.sh[31551]: libnsock nsock_trace_handler_callback(): Callback: TIMER SUCCESS for EID 52
Jul 29 21:31:50 kraken-zbox1 watchdog_tmp.sh[31551]: Ncat: Idle timeout expired (10000 ms).
Jul 29 21:31:50 kraken-zbox1 watchdog_tmp.sh[31551]: First failure after success resetting counter
Jul 29 21:31:50 kraken-zbox1 watchdog_tmp.sh[31551]: (0) ALARM!

我仍然想知道我做错了什么......

标签: linuxshellubuntu-18.04systemdnetcat

解决方案


经过一番搜索和与其他人交谈,我终于找到了我的问题:

ncat,当启动时,期望在标准输入上接收通过网络连接发送的输入,并将数据发送到标准输出。当你从 shell 启动我的脚本时,stdin 存在并且被正确地传送到 ncat 并且每个人都很高兴。另一方面, systemd不为其服务提供标准输入,因此没有标准输入会导致 ncat 终止,因为它没有任何东西可以发送。

一个简单--recv-only的 netcat 命令解决了这个问题,因此正确的脚本是:

#!/bin/bash
set -u

retry_counter=0
reader=""

echo "Starting"
while [[ $retry_counter -le 5 ]]; do
  # start bcat in reciever mode only!
  reader="$(ncat -v --recv-only -i 10 127.0.0.1 10001 2>&1 > /dev/null | tee >(cat >&2) )"
  if [[ "$reader" =~ "Connected" ]]; then
    echo "First failure after success resetting counter"
    retry_counter=0
  else
    (( retry_counter++ ))
  fi
  echo "($retry_counter) ALARM!"
  sleep 5
done

推荐阅读