亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

net.DialTCP 在 Linux 上產生“連接被拒絕”錯誤,但在 Windows 上沒有

net.DialTCP 在 Linux 上產生“連接被拒絕”錯誤,但在 Windows 上沒有

Go
RISEBY 2022-06-01 12:28:18
重現需要兩個應用程序運行并通過 TCP 相互連接。因此,我制作了一個包含 powershell 構建腳本的小型倉庫。鏈接到完整的回購但是為了避免額外的點擊,這里是clientA.go.package mainimport (    "fmt"    "net"    "time")func main() {    clientA, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf(":%v", "2222"))    if err != nil {        fmt.Println(err)        return    }    clientB, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf(":%v", "3333"))    if err != nil {        fmt.Println(err)        return    }    for {        clientAtoB, err := net.DialTCP("tcp4", clientA, clientB)        if err != nil {            fmt.Println(err)        } else {            defer clientAtoB.Close()            clientAtoB.SetLinger(0)            clientAtoB.SetNoDelay(true)            clientAtoB.SetKeepAlive(false)            fmt.Println("connected as Client A!")            buffer := make([]byte, 64)            _, err = clientAtoB.Read(buffer)            if err != nil {                continue            }        }        time.Sleep(time.Second)    }}的代碼clientB.go是相同的,只是交換了本地和遠程端點:clientBtoA, err := net.DialTCP("tcp4", clientB, clientA)
查看完整描述

1 回答

?
HUWWW

TA貢獻1874條經驗 獲得超12個贊

為什么這在 Linux 上不起作用是很明顯的。A 和 B 都是連接到需要監聽的對方的客戶端。在 Linux(或 UNIX)上,如果您嘗試運行 ClientA,它將嘗試撥入 ClientB 的地址和端口。如果在那一刻沒有進程已經在偵聽此地址和端口以接受連接,那么 ClientA 將立即以connection refused錯誤告終(這并不完全正確,但大多數情況下,請參閱答案末尾的我的編輯)。

在 Windows 上,Golang 在底層使用(用于 tcp、tcp4 和 tcp6 協議)ConnectExAPI,該 API 用于面向連接的套接字。此 API 的行為與 Linux connectAPI 不同。如果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(僅通過手動或從同一腳本運行兩個客戶端很難完成;即使在同一進程和線程中進行模擬也不是那么容易)。


查看完整回答
反對 回復 2022-06-01
  • 1 回答
  • 0 關注
  • 372 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號