1. 程式人生 > >c# 檢測網路斷線

c# 檢測網路斷線

最近我負責一個IM專案的開發,服務端和客戶端採用TCP協議連線。服務端採用C#開發,客戶端採用Delphi開發。在服務端開發中我碰到了各種各樣的網路異常斷開現象。在處理這些異常的時候有了一些心得,現在寫出來和大家分享一下。

那網路異常斷開原因主要有那些呢?歸納起來主要有以下兩種:

1、客戶端程式異常。

  對於這種情況,我們很好處理,因為客戶端程式異常退出會在服務端引發ConnectionReset的Socket異常(就是WinSock2中的10054異常)。只要在服務端處理這個異常就可以了。

2、網路鏈路異常。

  如:網線拔出、交換機掉電、客戶端機器掉電。當出現這些情況的時候服務端不會出現任何異常。這樣的話上面的程式碼就不能處理這種情況了。對於這種情況在MSDN裡面是這樣處理的,我在這裡貼出MSDN的原文:

如果您需要確定連線的當前狀態,請進行非阻止、零位元組的 Send 呼叫。如果該呼叫成功返回或引發 WAEWOULDBLOCK 錯誤程式碼 (10035),則該套接字仍然處於連線狀態;否則,該套接字不再處於連線狀態。

  但是我在實際應用中發現,MSDN說的這種處理方法在很多時候根本無效,無法檢測出網路已經異常斷開了。那我們該怎麼辦呢?

  我們知道,TCP有一個連線檢測機制,就是如果在指定的時間內(一般為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; //探測時間間隔(單位:毫秒)
};

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);
        }

好了,這樣就成功了。


文章整理:服務

以上資訊與文章正文是不可分割的一部分,如果您要轉載本文章,請保留以上資訊,謝謝!

相關推薦

c# 檢測網路

最近我負責一個IM專案的開發,服務端和客戶端採用TCP協議連線。服務端採用C#開發,客戶端採用Delphi開發。在服務端開發中我碰到了各種各樣的網路異常斷開現象。在處理這些異常的時候有了一些心得,現在寫出來和大家分享一下。 那網路異常斷開原因主要有那些呢?歸納起來主要有以下

netty4.0 心跳檢測重連操作

因為最近專案最近要用netty,服務端放在雲端,客戶端發在內網。那如何實現netty長連線和斷線重連呢(網路故障或者其他原因,客戶端要無限取重連服務端)。接下來我們看一下如何實現這個兩個功能呢。 服務端程式碼如下: package com.example.nettydem

C# 檢測網路資源是否有效

下載資料時,需要知道某個Web資源是否有效,其基本原理就是利用HTTP的HEAD方法,根據標頭返回的狀態碼,就可以確定資源是否有效了。 基本方法: /// <summary&g

C#實現adsl重連方法總結

using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Runtime.InteropServices; using System.Window

objective-c檢測網路狀態

Reachability *r = [Reachability reachabilityWithHostName:@"www.apple.com"]; switch ([r currentReachabilityStatus]) { case Not

C# 判斷Socket重連

定時器裡面的事件 private void isConnendTimer_Tick(object sender, EventArgs e) { // 首先,Socket類的Connected屬性只表示最後一次I/

Linux下使用UDP做心跳檢測檢測

何為心跳檢測   字型變大心跳檢測,顧名思義,就像心跳一樣客戶端每隔幾秒鐘傳送一個數據包(心跳包)給伺服器,告訴伺服器,客戶端還線上。如果伺服器在規定時間內沒有收到客戶端發來的心跳包,則認為客戶端已經掉線。   在我們日常生活中,很多地方都用到了心跳檢測機制

Netty — 心跳檢測重連

心跳檢測 limit art segment 檢測 oot 通過 context serve 一.前言 由於在通信層的網絡連接的不可靠性,比如:網絡閃斷,網絡抖動等,經常會出現連接斷開。這樣對於使用長連接的應用而言,當突然高流量沖擊勢必會造成進行網絡連接,從而產生網絡堵塞,

C# 網路連線中異常的處理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(設定心跳)

在使用 TcpClient 網路連線中常常會發生客戶端連線異常斷開, 服務端需要設定檢測手段進行這種異常的處理.    對於短連線, 通過對 Socket 屬性 ReceiveTimeout 和 SendTimeout 設定適當的值, 當在進行讀/寫時超時, 則會產生 SocketException 異

wifi網路為什麼總是 (by quqi99)

版權宣告:可以任意轉載,轉載時請務必以超連結形式標明文章原始出處和作者資訊及本版權宣告 (作者:張華 發表於:2018-09-28) 十一期間回老家隨身帶了一個小巧的LEDE韌體的小米青春版路由器, 但是遇到了一系統問題. 先是感覺wifi訊號大概隨機幾分鐘一斷, 去除錯吧又是好的, 剛

Teamviewer 檢測為商用用途,連線五分鐘解決辦法

一、引言 有沒有小夥伴工作中需要用到Teamviewer遠端桌面呢? 反正小編幾乎每天都需要用到。用著用著用著,直到某一天,突然只能連線五分鐘,網上也有各種的解決辦法。小編也找了破解版下載,結果都是徒

socket 通訊檢測客戶端非正常

package com.ist.socket; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.Fi

WebSocket在服務端和客戶端通訊demo,支援心跳檢測+重連

一、為什麼需要 WebSocket? 初次接觸 WebSocket 的人,都會問同樣的問題:我們已經有了 HTTP 協議,為什麼還需要另一個協議?它能帶來什麼好處? 答案很簡單,因為 HTTP 協議有一個缺陷:通訊只能由客戶端發起。 舉例來說,我們想了解今天的天氣,只能是客戶端向伺服器發出

C# 示例:檢測網路連線

       我們的應用程式的某些功能,可能需要一個網際網路連線的執行時間測試。一旦檢測到網際網路連線,可能會暫時被禁用的功能需要訪問Internet和/或使用者可以通過警報訊息通知。否則,應用程式可能會導致在操作過程中的錯誤,否則可能會導致惱人的問題.Method 1: W

Windows C語言 Socket程式設計 client端(客戶端)--重連版

瞭解了最基礎的C語言客戶端的編寫流程,稍稍加以改動即可實現斷線重連。 當伺服器掉線時,客戶端會以固定的頻率不停的重連。 #include <stdio.h> #include <winsock2.h> #pragma comme

即時通訊判斷網路狀態和重連機制

本文借鑑csdn大神way的xmpp客戶端學習改造而來,不足之處希望大家多多指教!  1. 由於近半年來一直寫針對於tigase伺服器的即時通訊軟體的開發,框架的重構,對即時通訊的理解也較之前更進一步,在客戶端的IM開發中,最重要的除去通訊的建立,就是保持網路環境不斷更換時

android——自動檢測網路變化,網彈出對話方塊提示

一、首先,建立一個類繼承BroadcastReceiver,重寫onReceive 方法 在onReceive方法中新增操作程式碼 二、在MainActivity中添加註冊操作 三、別忘了,在AndroidManifest.xml中新增許可權 <

SOCKET 檢測連結是否的三種方法

目前主要有三種方法來實現使用者掉線檢測:SO_KEEPALIVE ,SIO_KEEPALIVE_VALS 和Heart-Beat執行緒。 下面我就上面的三種方法來做一下介紹。 (1)SO_KEEPALIVE 機制         這是socket庫提供的功能,設定介面是se

手機客戶端弱網路下的重連處理

1、弱網路下的斷線重連   玩家在遊戲過程中,所處的網路環境是複雜多變的,可能是wifi的網路不穩定,或處在3G甚至2G的環境下等。在這些情況下,網路遊戲會由於網路或包量等原因而出現延遲,拉拽,甚至掉線等問題。對於這些問題,一方面要對程式的包量和通訊進行優化,從根本上減緩

Linux C 呼叫 ping命令 檢測網路狀態

int ping_status(char *ip) { int i, status; pid_t pid; printf(">>>>>>>>>>>>> ping_status\n "); // 不同則迴圈