91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

TCP連接檢測機制

發布時間:2020-08-01 15:50:10 來源:網絡 閱讀:1038 作者:螞蟻雄心 欄目:開發技術

采用TCP連接的C/S模式軟件,連接的雙方在連接空閑狀態時,如果任意一方意外崩潰、當機、網線斷開或路由器故障,另一方無法得知TCP連接已經失效,除非繼續在此連接上發送數據導致錯誤返回。很多時候,這不是我們需要的。我們希望服務器端和客戶端都能及時有效地檢測到連接失效,然后優雅地完成一些清理工作并把錯誤報告給用戶。

客戶端采用如下步驟:

1, 連接

2, 拔掉網線

經過以上兩步: 

 TCP連接檢測機制

從上圖中可以看到,此時服務端的連接依然存在。 

所以,tcp只是數據的發送與接收,包括握手,斷開以及rst,time_wait,close_wait 等等。

如何及時有效地檢測到一方的非正常斷開,一直有兩種技術可以運用。一種是由TCP協議層實現的Keepalive,另一種是由應用層自己實現的心跳包。

TCP默認并不開啟Keepalive功能,因為開啟Keepalive功能需要消耗額外的寬帶和流量,盡管這微不足道,但在按流量計費的環境下增加了費用,另一方面,Keepalive設置不合理時可能會因為短暫的網絡波動而斷開健康的TCP連接。并且,默認的Keepalive超時需要7,200,000 milliseconds,即2小時,探測次數為5次。就是如果在指定的時間內(一般為2個小時)沒有數據傳送,服務器會給對端發送一個Keep-Alive數據報(注意是由服務器主動發起),使用的序列號是曾經發出的最后一個報文的最后一個字節的序列號,對端如果收到這個數據,回送一個TCP的ACK,確認這個字節已經收到,這樣就知道此連接沒有被斷開。如果一段時間沒有收到對方的響應,會進行重試,重試幾次后,向對端發一個reset,然后將連接斷掉。

  在Windows中,第一次探測是在最后一次數據發送的兩個小時,然后每隔1秒探測一次,一共探測5次,如果5次都沒有收到回應的話,就會斷開這個連接。但兩個小時對于我們的項目來說顯然太長了。我們必須縮短這個時間。那么我們該如何做呢?我要利用Socket類的IOControl()函數。我們來看看這個函數能干些什么:

使用 IOControlCode 枚舉指定控制代碼,為 Socket 設置低級操作模式。 

命名空間:System.Net.Sockets 
程序集:System(在 system.dll 中) 

語法 

C# 
public int IOControl ( 
IOControlCode ioControlCode, 
byte[] optionInValue, 
byte[] optionOutValue 



參數 
ioControlCode 
一個 IOControlCode 值,它指定要執行的操作的控制代碼。 

optionInValue 
Byte 類型的數組,包含操作要求的輸入數據。 

optionOutValue 
Byte 類型的數組,包含由操作返回的輸出數據。 

返回值 
optionOutValue 參數中的字節數。

如:

 

socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);

 

我們要搞清楚的就是inOptionValues的定義,在C++里它是一個結構體。我們來看看這個結構體:

 

struct tcp_keepalive 

    u_long  onoff; //是否啟用Keep-Alive
    u_long  keepalivetime; //多長時間后開始第一次探測(單位:毫秒)
    u_long  keepaliveinterval; //探測時間間隔(單位:毫秒)
}; 

 

在C#中,我們直接用一個Byte數組傳遞給函數:

 

uint dummy = 0;
byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);//是否啟用Keep-Alive
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//多長時間開始第一次探測
BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);//探測時間間隔

 

具體實現代碼:

 

        public static void AcceptThread()
        {
            Thread.CurrentThread.IsBackground = true;
            while (true)
            {
                uint dummy = 0;
                byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
                BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
                try 
                {
                    Accept(inOptionValues);
                } 
                catch { } 
            } 
        } 

        private static void Accept(byte[] inOptionValues)
        {
            Socket socket = Public.s_socketHandler.Accept();
            socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
            UserInfo info = new UserInfo();
            info.socket = socket;
            int id = GetUserId();
            info.Index = id;
            Public.s_userList.Add(id, info);
            socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);
        } 

 

代碼摘自網絡


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿巴嘎旗| 陇南市| 喜德县| 象州县| 扶风县| 康乐县| 库车县| 滦平县| 喜德县| 息烽县| 谢通门县| 龙泉市| 哈尔滨市| 蚌埠市| 高平市| 兰州市| 开阳县| 澄迈县| 万载县| 呼图壁县| 蓝田县| 连城县| 霸州市| 清涧县| 逊克县| 铜梁县| 陇川县| 淮阳县| 龙门县| 武山县| 汉沽区| 饶河县| 北票市| 青冈县| 新干县| 新和县| 大姚县| 上思县| 施甸县| 彭州市| 迁安市|