1 回答

TA貢獻1874條經驗 獲得超12個贊
為什么這在 Linux 上不起作用是很明顯的。A 和 B 都是連接到需要監聽的對方的客戶端。在 Linux(或 UNIX)上,如果您嘗試運行 ClientA,它將嘗試撥入 ClientB 的地址和端口。如果在那一刻沒有進程已經在偵聽此地址和端口以接受連接,那么 ClientA 將立即以connection refused
錯誤告終(這并不完全正確,但大多數情況下,請參閱答案末尾的我的編輯)。
在 Windows 上,Golang 在底層使用(用于 tcp、tcp4 和 tcp6 協議)ConnectEx
API,該 API 用于面向連接的套接字。此 API 的行為與 Linux connect
API 不同。如果ConnectEx
無法立即連接,它會返回錯誤代碼ERROR_IO_PENDING
,并且操作系統會在后臺等待/重試,直到連接被接受并建立(或者它放棄并使其最終失?。?,然后通知回來 - 這稱為重疊 I/O。
MSDN ConnectEx 文檔的相關部分:
面向連接的套接字通常無法立即完成它們的連接,因此會啟動操作并且函數會立即返回 ERROR_IO_PENDING 或 WSA_IO_PENDING 錯誤。當連接操作完成并實現成功或失敗時,使用 lpOverlapped 中指示的完成通知機制報告狀態。
現在,您在 Windows 上發生的情況是您嘗試ConnectEx
從雙方和操作系統為您連接這些套接字。這僅在另一端在一定時間內連接時才有效。如果您嘗試合理地增加time.Sleep
兩個客戶端的間隔(例如 17 和 28),您甚至可以在 Windows 上看到它們將很難再連接。
對您的問題的回答是,您現在編寫的代碼取決于 Windows 上 Golang 中 TCP 撥號的操作系統特定行為,并且不可移植。要將您的軟件修復為在 Golang 支持的任何平臺上可移植,您可能需要更改邏輯,以便 ClientA 和 ClientB 都偵聽傳入連接并定期嘗試連接到另一端。
編輯:我并不是說您的代碼根本無法在 Linux 上運行。它實際上使用稱為TCP 同時連接的罕見連接模式,您可以在其中連接兩個進程而無需其中任何一個listen
。撥號雙方同時發送他們的 SYN,因此每一方都以 SYN/ACK 和 ACK 響應,以完成 3 次握手和 ESTABLISH 連接。connect
這需要非常精確的時間和兩個客戶端中的呼叫同步。如果 Linux 內核中允許 TCP 同時連接并且實現了 s 之間的同步,則雙方都會連接connect
(僅通過手動或從同一腳本運行兩個客戶端很難完成;即使在同一進程和線程中進行模擬也不是那么容易)。
- 1 回答
- 0 關注
- 372 瀏覽
添加回答
舉報