/ dev / udp和netcat之间的区别

我有一个系统日志服务器监听本地主机:514作为UDP,并希望在该端口上写入消息。 (使用Ubuntu 14.04)

如果我从bash运行这些命令中的任何一个,它将每2秒钟将date打印到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 

现在只是为了testing我杀死系统日志服务器的事情,然后几秒钟后启动它。

当系统日志进程死了的时候,/ dev / udp命令每两秒打印一次到控制台,所以它认为没有localhost:514来写入。 一旦系统日志回来,这些连接被拒绝的消息将停止,并恢复将date写入系统日志。 这是预期的。

 date: write error: Connection refused 

但netcat命令不会这样做。 当系统日志进程死了,它不会输出任何输出到控制台。 当syslog回来时,它不会继续将date写入syslog。

为什么当syslog重新启动时,netcat会继续写入localhost:514? 我怎样才能让netcat按照/ dev / udp在这个例子中的方式行事?

这似乎是一个错误在ncnc命令使用poll系统调用来等待,直到从stdin或套接字接收到input。

当一个UDP包被发送到接收端的一个closures的UDP端口时,会发送一个错误消息。 poll调用将把这个状态返回给nc命令,但是nc实际上并没有处理这个错误。 相反, nc返回再次调用poll系统调用,由于错误仍然在套接字上排队,这会立即返回。

这可能是一个无限循环,在这个循环中, nc会消耗所有CPU时间,从而无用。

但是它只能持续到stdin接收到下一条消息。 此时poll将两个状态都返回给ncnc处理来自stdin的数据。 现在nc会尝试从stdin写入数据到套接字。 写入套接字的尝试将把排队的错误传递给nc 。 写入错误信息将导致nc终止。

这给你留下了一个坏的pipe道(即一个pipe道,但没有阅读器)。 任何试图写入pipe道的操作都会触发一个SIGPIPE信号,如果SIGPIPE没有SIGPIPE这个进程,那么写入调用会产生一个错误。

date不处理SIGPIPE ,所以date被杀死。 所以这个循环继续下去,但是每当试图写入到读者已经离开的pipe道时,每一个date都会被终止。

什么可以做

尽pipe循环调用系统调用的nc循环而不提交错误肯定是一个错误,修复这个错误不一定能够满足你的需要。 简单地终止一旦从poll返回错误可能被认为是nc的正确的错误修正。 人们可以设想一个额外的function,如果给定一个特定的标志, nc可以被告知在错误之后继续前进。

但是你可以通过简单的重新启动nc来解决这个问题:

 while sleep 1 ; do date ; done | while true ; do nc -u localhost 514 ; done 

nc导致CPU周期性过度使用的bug仍然存在。 此外,该错误和解决方法的组合可能导致接收端口重新打开后丢失的第一条消息。