本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威在線客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。
請訪問:https://kf.shengxunwei.com
演示網絡中斷,直接禁用網卡,或者手機進入飛行模式,也不丟消息,不出異常。
視頻地址:https://v.youku.com/v_show/id_XNTEwNzQ5Mzg2OA==.html
TCP 報文的確認機制
首先我們回顧一下 TCP 協議,TCP 報文格式一般如下所示:
其中的 ACK ,表示對報文是否送達的一個回應。
ACK是TCP標頭中的標志和字段。 發送一個消息至少需要一個標頭,再加上所有較低層的內容。
下圖則顯示了 TCP 通信時,客戶端和服務端之間報文傳送的過程。
從圖中可以看到,發出的消息,和回應的消息,都會有一個編號,如:#1、#2
在ACK報文回應時,它回附帶上所收到的報文的編號,那么發送端只需根據收到的ACK報文中的編號,就能判定報文是否送達,已經所送達的數據包。如果在一定時間內,沒有收到回應的ACK消息,則發送端會在一定時間內重新嘗試發送。
通過 C# 實現拔網線也不丟消息的高可靠通信
基於 TCP 協議自有的消息確認機制,我們在上層應用中實現可靠的通信就比較簡單了。底層通信相關的類已經幫我們實現好了可靠的 TCP 傳輸,一旦出現網絡異常,我們在上層都能夠收到相應的通知。
客戶端自身網絡異常
這種情況最好處理。因為客戶端程序異常退出會直接引發 ConnectionReset 的 Socket 異常。我們只需要在服務端捕獲這個異常進行處理即可:
public bool Send(byte[] data)
{
// 連接已經斷開了
try
{
_networkStream.Write(data, 0, data.Length);
}
catch (Exception ex)
{
OnDisconnected(ex);
return false;
}
return true;
}
網絡鏈路異常
對於這種情況,我們只需要檢測 Socket 對象的 Connected 屬性。
但是需要特別注意:Socket 對象的 Connected 屬性獲取從 Socket 最后一個 i/o 操作到的的連接狀態。 當它返回時 false , Socket 要么從未連接,要么不再處於連接狀態。當 Socket 從另一個線程斷開連接時,它可能會在操作中止后返回。
如果需要確定連接的當前狀態,請發出非阻止的零字節發送調用。 如果調用成功返回或引發 WAEWOULDBLOCK 錯誤代碼 (10035) ,則套接字仍處於連接狀態;否則,將不再連接套接字。
我們可以通過實現一個定時心跳,來對網絡鏈路進行檢測:
_heartbeatTimer = new Timer((state) =>
{
HeartbeatMessage heartbeatMessage = new HeartbeatMessage();
Send(heartbeatMessage);
}, null, 3000, 3000);
在定時器發送心跳時,如果網絡鏈路中斷,我們可以收到以下消息:
private void _socketClient_Disconnected(object sender, EventArgs e)
{
if (_heartbeatTimer != null)
_heartbeatTimer.Dispose();
if (_socketClient != null)
{
_socketClient.Close();
_socketClient = null;
}
}
只需針對 Disconnected 事件,進行處理,將兩端的狀態,置於等待即可。
請訪問:https://kf.shengxunwei.com
聯系QQ: 279060597
聯系E-mail:C5118@outlook.com