Python

具有高 RTT 和重傳的套接字 TCP 伺服器

  • August 21, 2016

我有一個用 Python 中的套接字建構的 TCP 伺服器。我正在建構的應用程序是時間敏感的,因此數據的完整性很重要,因此我們需要 TCP。頻寬非常低。

還有一個客戶端每 50 毫秒向伺服器請求一次數據。如果伺服器沒有數據或實際需要的數據,客戶端會收到一條 OK 消息作為響應。

每當客戶端向伺服器發出請求時,它都會發送一個 5 個字節的幀(不包括來自 IP 和 TCP 的 40 個額外字節)。另一方面,伺服器要麼以 5 字節的幀(在大多數情況下)或 > 70 字節的幀(通常每秒)響應

兩側的插座設置如下:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # this line is excluded in client's case
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(0.5)

一切在本地網路上執行良好(完全沒有延遲),但是每當我從公共 IP 連接到伺服器(我是埠轉發)時,它就會滯後很多。延遲可以達到 15 秒(在那一刻它超時),這是非常多的。大多數時候,RTT 保持在 200-210 毫秒。在 WireShark 上,我可以看到有很多(虛假的)重傳和重複 ACK。

我能做些什麼?我已經禁用了 Nagle 的算法,但還沒有成功。

我仔細查看了提供的擷取文件,這是我的分析。總之,我認為這是您的路由器的問題,它似乎是某種Technicolor設備。

客戶端擷取

  • 您的客戶在嘗試連接到各種網站時遇到了重大問題。HTTPS 網站(www.bing.com、wdcp.microsoft.com 等)在客戶端 Hello 階段後沒有響應,導致重新傳輸並最終從您的設備超時。對 Akamai 託管網站 (104.90.152.18) 的另一組 HTTP 請求導致 408 請求超時。
  • 專門查看從客戶端到伺服器的流量,絕大多數會話開始時還算正常,但隨後遇到封包遺失,導致客戶端重新傳輸和超時。例如,檢查數據包編號 161 - 207。在數據包 161 處,客戶端向伺服器發送數據包但沒有得到響應,導致客戶端在連接斷開之前重新傳輸大約 15 秒。

大多數 TCP 流都展示了這種行為,因此我們可以得出結論,要麼來自客戶端的數據包沒有到達伺服器,要麼來自伺服器的響應沒有到達客戶端。

  • 從延遲來看,伺服器的 SYN 和 SYN/ACK 響應之間存在顯著(且不穩定)的延遲,範圍從 168 毫秒到 770 毫秒。

伺服器端擷取

  • 不幸的是,伺服器端擷取不會擷取與客戶端擷取相同的事件。我也不確定這在網路中的確切位置被擷取,因為它包括客戶端和伺服器流量。ICMP 重定向也被發送,這表明路由不是最優的。但是,我不認為這會導致問題。
  • 如果您應用 wireshark 顯示過濾器,tcp.stream eq 1 || tcp.stream eq 2您可以看到通信的雙方。具體來說,客戶端 > 防火牆,然后防火牆 > 伺服器(反之亦然)。同樣,一切都開始正常,然後圍繞數據包 407 事情變得有趣。

數據包 #407 標誌著客戶端向伺服器發送一大塊新數據的時間點。路由器收到此資訊並將其轉發給伺服器。伺服器發回一個確認包(包#410)以及另一個小數據包(#411)。然而,我們沒有看到路由器將這些數據包傳回客戶端——這是我發現這是路由器問題的最佳證據。

將此與跟踪中稍稍靠前的許多成功交換之一進行比較 - 例如數據包 394 到 406:

  1. (#394) 客戶端向伺服器的公網 IP 發送數據包
  2. (#396) 路由器接收到這個並將其轉發到伺服器的本地 IP
  3. (#397) 伺服器向客戶端的 NAT 後 IP 發送確認
  4. (#398) 伺服器將一個小數據包發送回客戶端的 NAT’d IP
  5. (#401) 路由器將確認發送回客戶端的本地 IP
  6. (#402) 路由器將小數據包發送回客戶端的本地 IP
  7. (#403) 客戶端向伺服器的公共 IP 發送一個確認,以確認它收到了伺服器發送的數據
  8. (#406) 路由器將確認轉發到伺服器的本地 IP。

當事情失敗時,在第 4 階段之後一切都停止了——從伺服器發送的兩個數據包似乎在路由器上被丟棄了。

最後的想法

  • 您的大多數 TCP 連接,而不僅僅是您的 Python 應用程序,似乎都遇到了性能問題,正如您的客戶端擷取中的許多連接問題所證明的那樣。
  • 在您的伺服器端擷取中有合理的證據表明,當必須通過您的路由器轉發數據包時,它們正在被黑洞。
  • 您的測試得出的結論是,在本地測試此應用程序時沒有問題,當流量不需要通過路由器進行埠轉發時。
  • 不幸的是,我根本不熟悉 Technicolor 路由器,我唯一能建議的就是檢查路由器上是否啟用了任何可能影響性能的防火牆或服務質量規則。也許您可以使用替代路由器進行測試或將您的應用程序託管在另一個網路中以查看問題是否仍然存在。

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