問題描述
兩個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);