C# UDP通訊 ReceiveAsync() 一直等待問題

Zzz1207發表於2024-10-17

問題描述

兩個C#應用,一個作為服務端Server,另一個作為客戶端Client,客戶端開啟一個Udp埠,迴圈接收資料;服務端開啟後向客戶端傳送指令,當服務端出現異常時關閉了服務端的UdpClient,此時客戶端卡死在_client.ReceiveAsync(),無法再接收到訊息。
客戶端程式碼:

try
{
    var cts = new CancellationTokenSource();
    var client = new UdpClient(new IPEndPoint(IPAddress.Any, 10000));
    Task.Run(async () => 
    {
        while (true) 
        {
            await Task.Delay(100, cts.Token).ConfigureAwait(false);
            if (_client != null && _client.Available != 0) 
            {
                if(cts.Token.IsCancellationRequested) break;
                var res = await _client.ReceiveAsync().ConfigureAwait(false);
                if (res.Buffer != null && res.Buffer.Length > 0) 
                {
                    Console.WriteLine(res.Buffer);
                }
            }
        }
    }, cts.Token);
}
catch(Exception e)
{

}

服務端UdpClient關閉後,客戶端catch陷入無限等待,且無法捕獲到異常,服務端重啟後也無法再次接收服務端訊息。

解決方案:服務端斷開後,客戶端會收到遠端主機關閉連線的異常,將異常捕獲移動到內部,並捕獲SocketException異常,當捕獲到的異常程式碼為ConnectionReset時,表示遠端主機關閉,不做處理即可,下次服務端重啟後可正常連線。

var cts = new CancellationTokenSource();
var client = new UdpClient(new IPEndPoint(IPAddress.Any, 10000));
Task.Run(async () => 
{
    while (true) 
    {
        await Task.Delay(100, cts.Token).ConfigureAwait(false);
        if (_client != null && _client.Available != 0) 
        {
            if(cts.Token.IsCancellationRequested) break;
            try
            {
                var res = await _client.ReceiveAsync().ConfigureAwait(false);
                if (res.Buffer != null && res.Buffer.Length > 0) 
                {
                    Console.WriteLine(res.Buffer);
                }
            } 
            catch (SocketException ex) 
            {
                if(ex.SocketErrorCode == SocketError.ConnectionReset)
                {
                    //遠端主機關閉連線
                }
                // 處理接收超時或其他異常
                else Console.WriteLine($"Socket exception: {ex.Message}");
            }
        }
    }
}, cts.Token);

相關文章