c# – 配置套接字ACK超時?
在確定連線失敗之前,是否有辦法配置套接字期望接收發送資料的ACK的超時時間?
我知道這可以在應用程式級別完成,但是由於我傳送的每個資料包都是ACK,我只想知道我的資料是否被接收,在應用程式級使用附加資料來完成相同的操作事情似乎很浪費. (更不要說,我的特定應用程式使用每位元組充電的蜂窩鏈路.)
注意:根據我以前的問題 –
ofollow,noindex" target="_blank">What conditions cause NetworkStream.Write to block? – 你不能依靠.Write丟擲異常,以確定資料沒有正確傳送.
這是一個古老的問題,但它與我在一起回家…正如你原來的問題所暗示的那樣,應該在應用層完成.
我希望我的經驗可能是有幫助的,因為我有完全相同的想法(甚至與我的團隊的其他開發人員爭取這個堅持的TCP應該完成工作).實際上,它很容易使TCP與無線連線,衝突的網路MTU和有時執行不良的路由器/接入點過早地或在故障條件下進行.而且因為TCP旨在從一個源流傳輸到一個目的地,而不是真正地確保全雙工處理的通訊.
我花了幾年時間為嵌入式裝置製造商工作,為倉庫中的無線條形碼終端寫了一個完整的客戶端 – 伺服器系統.在這種情況下不是蜂窩的,但是WiFi可以是一樣糟糕(但即使WiFi將證明所需的任務無用). FYI,近7年來,我的系統在生產中仍然可靠執行,所以我認為我的實施是相當穩健的(經歷工業製造機器/焊工/空氣壓縮機/老鼠咀嚼網路線等的干擾).
瞭解問題
@rodolk釋出了一些很好的資訊. TCP級別的ACK不一定對應於您的每個應用程式網路傳輸(如果傳送超過網路的MTU或最大資料包大小,即使Nagle被禁用,也不一定是1-1).
>IP Datagram Size, the Maximum Transmission Unit (MTU), and Fragmentation Overview
>Dealing with Fragmented Traffic
>Wireless Networking MTU – Physical MTU vs Logical Packet Size
最終,TCP& IP(Transport and Network layers )將確保您的流量在一個方向(從源到目的地)交付,並且對最大重試次數有一些限制.應用通訊最終涉及位於TCP / IP之上的全雙工(雙向)Application layer 通訊.混合這些層不是一個好的策略.想想在TCP / IP之上的HTTP請求響應. HTTP不依賴TCP ACKS實現自己的超時等.如果你有興趣,HTTP將是一個很好的規範.
但是我們甚至假裝它正在做你想要的事情.您始終在1個傳輸中傳送少於1個MTU(或最大包大小),並且正好接收1個ACK.介紹您的無線環境,一切都變得更加複雜.您可以在成功傳輸和相應的ACK之間發生故障!
問題是無線通訊流的每個方向不一定具有相同的質量或可靠性,並且可以基於本地環境因素和無線裝置的移動隨著時間而改變.
裝置通常比他們可以傳輸更好.裝置接收傳輸是很常見的,用某種傳輸的“ACK”進行回覆,但由於訊號質量,傳輸距離,射頻干擾,訊號衰減,訊號反射等原因,無線ACK無法到達目的地在工業應用中,這可能是重型機械開關,焊接機,冰箱/冷櫃,熒光燈等.在城市環境中,可能是結構,停車庫,鋼結構建築物等內的移動.
在這種情況下,客戶端在什麼時候採取行動(儲存/提交資料或更改狀態),以及伺服器在何時認為操作成功(儲存/提交資料或更改狀態)?這在應用層中無需額外的通訊檢查就非常難以解決(有時包括用於事務的雙向ACK,即:客戶端傳送,伺服器ACKS,客戶端確認ACK :-)您不應該依賴於TCP級別的ACK,因為它們將無法可靠地等同於成功的全雙工通訊,並且不會為您的應用程式提供可靠的重試機制.
嵌入式裝置不可靠無線通訊的應用層技術
我們的技術是每個應用程式級別的訊息都被髮送到一個包含資料包ID(只是一個遞增整數)的位元組應用程式級頭,位元組的整個訊息的長度以及整個訊息的CRC32校驗和.我不記得了,但我相信我們這樣做是8位元組,2 | 2 | (取決於您要支援的最大訊息長度).
所以假設你在倉庫裡盤點庫存,你會計數一個專案並計數5個單位,條形碼終端向伺服器傳送一條訊息,說“本計算了5個單位的專案1234”.當伺服器接收到訊息時,它將等到接收到完整的訊息,首先驗證訊息長度,然後驗證CRC32校驗和(如果長度匹配).如果這一切都通過,我們將回復應用程式的響應傳送給該訊息(類似於應用程式的ACK).在此期間,條形碼終端正在等待來自伺服器的ACK,並且如果沒有從伺服器回來,將重新發送.如果伺服器接收到相同資料包ID的多個副本,則可以通過放棄未提交的事務來取消複製.然而,如果條形碼掃描器從伺服器接收到ACK,那麼它將再次向伺服器回覆最後一個“COMMIT”命令.因為前兩個訊息剛剛驗證了一個工作的全雙工連線,所以提交在這幾個ms時間段內難以想象. FYI,這種故障條件在您的WiFi覆蓋的邊緣很容易複製,所以拿你的膝上型電腦/裝置去散步,直到WiFi只是“1 bar”,或最低的連線速度通常是1 mbps.
所以你要在訊息的開始新增8個位元組的頭,如果只需要一個無線通訊的一方可能會失敗,可以選擇新增一個額外的最後的COMMIT訊息傳輸.
通過複雜的應用層儲存每個訊息的8個位元組來傳輸層掛鉤系統(例如掛接到winpcap)將是非常困難的.此外,您可能或可能無法複製掛在其他裝置上的傳輸層(也許您的系統將來會在其他裝置上執行?Android,iOS,Windows Phone,Linux可以為所有這些實現相同的應用層通訊平臺?我認為您應該能夠在每個裝置上實現應用程式,而不管TCP堆疊如何實現.)
我建議您將應用層與運輸和網路層分開,以便很好地分離問題,並嚴格控制重試條件,超時和可能處理的應用程式狀態更改.
http://stackoverflow.com/questions/7667633/configure-socket-ack-timeout