gpt4 book ai didi

c# - 如何正确关闭持久的 System.Net.WebSockets.ClientWebSocket 连接?

转载 作者:太空宇宙 更新时间:2023-11-03 14:41:31 25 4
gpt4 key购买 nike

我正在使用 System.Net.WebSockets.ClientWebSocket 创建一个 C# WebSocket 客户端以连接到我不拥有源代码的服务器。到目前为止一切正常,但我希望“正确”断开我的客户端。这是我的源代码的缩写版本:

public class Client : IDisposable
{
private ClientWebSocket socket;
private string endpoint;
private Task receiveTask;

public Client(string endpoint)
{
this.endpoint = endpoint;
this.socket = new ClientWebSocket();
}

public async Task Initialize()
{
byte[] contentBuffer = Encoding.UTF8.GetBytes("notify message");

// Connect to the server, and send a message to notify
// it of the client's availability to receive data.
await OpenConnection();
await socket.SendAsync(new ArraySegment<byte>(contentBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
}

private async Task OpenConnection()
{
if (socket.State != WebSocketState.Open)
{
await socket.ConnectAsync(new Uri(endpoint), CancellationToken.None);
receiveTask = Task.Run(async () => await Receive());
}
}

private async Task Receive()
{
while (socket.State == WebSocketState.Open)
{
byte[] buffer = new byte[1024];
var result = await m_sessionSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);

if (result.MessageType == WebSocketMessageType.Close)
{
break;
}
else
{
using (var stream = new MemoryStream())
{
stream.Write(buffer, 0, result.Count);
while (!result.EndOfMessage)
{
result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
stream.Write(buffer, 0, result.Count);
}

stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
string message = reader.ReadToEnd();
// Do stuff with received message
}
}
}
}
}

public void Dispose()
{
// NOTE: This is a gross oversimplification. Assume in the
// actual project that a proper implementation of the Dispose
// pattern has been created.
if (socket.State == WebSocketState.Open)
{
// How do I notify the server of disconnection?
// The below has some sort of race condition, whereby
// it hangs the client.
Task.Run(async () => await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None)).Wait();
}

if (receiveTask != null)
{
receiveTask.Dispose();
}

socket.Dispose()
}
}

现在是我面临的挑战。在数据接收完成之前,我无法处理运行数据接收的 Task。该任务被阻止等待从服务器接收。尝试从 Dispose 中调用 CloseAsync 似乎会遇到某种死锁,因此这可能不是正确的方法。

显然,我可以使用 CancellationTokenSourceCancellationToken 传递给 Receive 方法,然后将其传递给 ReceiveAsync WebSocket 的方法。如果我这样做并告诉 token 源标记 token ,它将释放该 block ,我可以在接收方法中检查 token 中的 IsCancellationRequested 标志,当看到它时退出。但是,如果我这样做,它会抛出异常。我真的需要在我的 Dispose 方法中捕获异常(糟糕!)只是为了取消任务吗?另外,如果我取消任务,是否会正确通知服务器断开连接?还是我一开始就让长时间运行的(非等待的)Task 运行 ReceiveAsync 方法来做错?

最佳答案

在这种情况下,您不应使用 IDisposable。优雅地关闭 websocket 连接涉及异步 I/O。它需要一个干净的“关闭握手”,即发送方发送一个 CLOSE 帧并且接收方发回一个 CLOSE 帧。只有这样,连接才会过渡到干净的套接字关闭(使用 FIN 而不是 RST)。

如果您需要“IDisposable”语义,您可以查看最新的 .NET Core 中引入的新 IAsyncDisposable 模式。但总的来说,使用同步 Dispose() 模式并不是一个好主意。

关于c# - 如何正确关闭持久的 System.Net.WebSockets.ClientWebSocket 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56694527/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com