1. 程式人生 > >.net core 和 WPF 開發升訊威線上客服系統:怎樣實現拔網線也不丟訊息的高可靠通訊(附視訊)

.net core 和 WPF 開發升訊威線上客服系統:怎樣實現拔網線也不丟訊息的高可靠通訊(附視訊)

本系列文章詳細介紹使用 .net core 和 WPF 開發 升訊威線上客服與營銷系統 的過程。本產品已經成熟穩定並投入商用。 線上演示環境:[https://kf.shengxunwei.com](https://kf.shengxunwei.com) 注意:演示環境僅供演示交流與評估,不保證 7x24 小時可用。 [文章目錄列表請點選這裡](https://blog.shengxunwei.com/Home/Post/44a31a32-d4e1-4ddd-8526-8a2bcd2e22be) --- 演示網路中斷,直接禁用網絡卡,或者手機進入飛航模式,也不丟訊息,不出異常。 視訊地址:[https://v.youku.com/v_show/id_XNTEwNzQ5Mzg2OA==.html](https://v.youku.com/v_show/id_XNTEwNzQ5Mzg2OA==.html) --- ### TCP 報文的確認機制 首先我們回顧一下 TCP 協議,TCP 報文格式一般如下所示: 其中的 ACK ,表示對報文是否送達的一個迴應。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221094439731.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ljY2IxMDEz,size_16,color_FFFFFF,t_70) ACK是TCP標頭中的標誌和欄位。 傳送一個訊息至少需要一個標頭,再加上所有較低層的內容。 下圖則顯示了 TCP 通訊時,客戶端和服務端之間報文傳送的過程。 從圖中可以看到,發出的訊息,和迴應的訊息,都會有一個編號,如:#1、#2 在ACK報文迴應時,它回附帶上所收到的報文的編號,那麼傳送端只需根據收到的ACK報文中的編號,就能判定報文是否送達,已經所送達的資料包。如果在一定時間內,沒有收到迴應的ACK訊息,則傳送端會在一定時間內重新嘗試傳送。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221094304313.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ljY2IxMDEz,size_16,color_FFFFFF,t_70) ### 通過 C# 實現拔網線也不丟訊息的高可靠通訊 基於 TCP 協議自有的訊息確認機制,我們在上層應用中實現可靠的通訊就比較簡單了。底層通訊相關的類已經幫我們實現好了可靠的 TCP 傳輸,一旦出現網路異常,我們在上層都能夠收到相應的通知。 #### 客戶端自身網路異常 這種情況最好處理。因為客戶端程式異常退出會直接引發 ConnectionReset 的 Socket 異常。我們只需要在服務端捕獲這個異常進行處理即可: ~~~ csharp 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) ,則套接字仍處於連線狀態;否則,將不再連線套接字。 我們可以通過實現一個定時心跳,來對網路鏈路進行檢測: ~~~ csharp _heartbeatTimer = new Timer((state) => { HeartbeatMessage heartbeatMessage = new HeartbeatMessage(); Send(heartbeatMessage); }, null, 3000, 3000); ~~~ 在定時器傳送心跳時,如果網路鏈路中斷,我們可以收到以下訊息: ~~~ csharp 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](https://kf.shengxunwei.com) 注意:演示環境僅供演示交流與評估,不保證 7x24 小時可用。 聯絡QQ: 279060597 聯絡E-mail:C5118@outl