我有一个以 UDP 形式监听的系统日志服务器localhost:514
,我想通过该端口向其写入消息。(使用 Ubuntu 14.04)
如果我从 bash 运行这些命令中的任何一个,它会每 2 秒将日期打印到 syslog
# Using netcat
while true; do sleep 2; date; done | nc -u localhost 514
# Using /dev/udp
while true; do sleep 2; date; done > /dev/udp/localhost/514
现在只是为了测试一下,我关闭了 syslog 服务器,然后在几秒钟后启动它。
当 syslog 进程停止时,该/dev/udp
命令每 2 秒会向控制台打印一条错误消息,因此它认识到没有localhost:514
可供写入的内容。
date: write error: Connection refused
一旦系统日志恢复,这些连接被拒绝的消息就会停止,系统日志会继续将日期写入系统日志。这是预期的。
但是 netcat 命令不会这样做。当 syslog 进程停止时,它不会将任何输出打印到控制台。当 syslog 恢复时,它不会继续将日期写入 syslog。
为什么 syslog 重新启动后,netcat 不会继续写入 localhost:514?我怎样才能让 netcat/dev/udp
按照本例中的方式运行?
答案1
这似乎是 中的一个错误nc
。该nc
命令使用系统调用来等待,直到从或 套接字poll
接收到输入。stdin
当 UDP 数据包被发送到接收端已关闭的 UDP 端口时,将返回一条错误消息。该poll
调用会将此状态返回给nc
命令,但nc
实际上不会处理错误。而是nc
返回再次调用poll
系统调用,由于错误仍在套接字上排队,因此系统调用会立即返回。
这可能是一个无限循环,它将nc
消耗所有的 CPU 时间,而无用处。
但是它只持续到在 上收到下一条消息为止stdin
。此时poll
将两个状态都返回到nc
,后者处理来自 的数据stdin
。现在nc
将尝试将来自 的数据写入stdin
套接字。尝试写入套接字会将排队错误传递给nc
。写入错误消息将导致nc
终止。
这会导致管道损坏(即管道有写入器但没有读取器)。任何写入管道的尝试都会触发信号SIGPIPE
,如果进程没有被SIGPIPE
写入调用的错误杀死,则会触发信号。
date
无法处理SIGPIPE
,因此date
被终止。因此循环继续,但每次date
尝试写入管道时都会被终止,而读取器早已不存在了。
可以做什么
虽然nc
在系统调用中循环poll
而不处理错误肯定是一个错误,但修复该错误不一定足以满足您的需求。一旦从 返回错误,简单地终止可能poll
被认为是 的正确错误修复nc
。可以想象一个附加功能,nc
如果给出特定标志,可以告诉 在哪里在发生错误后继续运行。
但是您可以通过简单地重新启动 nc 来解决该问题,如下所示:
while sleep 1 ; do date ; done | while true ; do nc -u localhost 514 ; done
导致 中周期性 CPU 使用率过高的 bugnc
仍然存在。此外,该 bug 和解决方法的结合可能会导致接收端口重新打开后的第一条消息丢失。