/dev/udp 和 netcat 的區別
我有一個 syslog 伺服器
localhost:514
作為 UDP 偵聽,並希望在該埠上向其寫入消息。(使用 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 程序停止時,該
/dev/udp
命令每 2 秒向控制台列印一條錯誤消息,因此它辨識出沒有localhost:514
可寫入的內容。date: write error: Connection refused
一旦 syslog 恢復,這些連接被拒絕的消息就會停止,它會繼續將日期寫入 syslog。這正如預期的那樣。
但是 netcat 命令不這樣做。雖然 syslog 程序已死,但它不會將任何輸出列印到控制台。當 syslog 返回時,它不會繼續將日期寫入 syslog。
為什麼重新啟動 syslog 時 netcat 不會繼續寫入 localhost:514?我怎樣才能讓 netcat 表現得像
/dev/udp
這個例子中的那樣?
這似乎是
nc
. 該nc
命令使用poll
系統呼叫來等待,直到從其中一個stdin
或套接字接收到輸入。當一個 UDP 數據包被發送到接收端的一個關閉的 UDP 埠時,一個錯誤資訊被發回。
poll
呼叫會將此狀態返回給命令nc
,但nc
不會實際處理錯誤。而是nc
返回再次呼叫poll
系統呼叫,由於錯誤仍在套接字上排隊,該系統呼叫立即返回。這可能是一個無限循環,
nc
它將消耗所有 CPU 時間,它可能無用做任何事情。然而,它只持續到收到下一條消息
stdin
。此時poll
將兩種狀態都返回到nc
,它處理來自 的數據stdin
。現在nc
將嘗試將數據從stdin
套接字寫入。寫入套接字的嘗試會將排隊的錯誤傳遞到nc
. 寫入錯誤消息將導致nc
終止。這會給您留下一個損壞的管道(即一個有作家但沒有讀者的管道)。任何寫入管道的嘗試都會觸發一個
SIGPIPE
信號,並且如果程序沒有被SIGPIPE
write 呼叫的錯誤殺死。
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 使用率過高的錯誤
nc
仍然存在。此外,該錯誤和解決方法的組合可能會導致重新打開接收埠後的第一條消息失去。