Networking

/dev/udp 和 netcat 的區別

  • December 17, 2019

我有一個 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信號,並且如果程序沒有被SIGPIPEwrite 呼叫的錯誤殺死。

date不處理SIGPIPE,所以date被殺。所以循環繼續進行,但每次date嘗試寫入閱讀器早已不在的管道時都會被殺死。

可以做什麼

儘管ncpoll不處理錯誤的情況下循環系統呼叫絕對是一個錯誤,但修復該錯誤不一定足以滿足您的需求。一旦錯誤返回,簡單地終止poll可能被認為是正確的錯誤修復nc。可以想像一個額外的功能,nc如果給定一個特定的標誌,可以告訴它在錯誤之後繼續前進。

但是你可以通過簡單地在這樣的循環中重新啟動 nc 來解決這個問題:

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

導致周期性 CPU 使用率過高的錯誤nc仍然存在。此外,該錯誤和解決方法的組合可能會導致重新打開接收埠後的第一條消息失去。

引用自:https://serverfault.com/questions/616267