gpt4 book ai didi

c# - 将 Socket.ReceiveAsync 替换为 NetworkStream.ReadAsync(可等待)

转载 作者:可可西里 更新时间:2023-11-01 08:54:51 29 4
gpt4 key购买 nike

我有一个应用程序可以同时建立几百个 TCP 连接,并从它们接收源源不断的数据流。

 private void startReceive()
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += receiveCompleted;
e.SetBuffer(new byte[1024], 0, 1024);
if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}

void receiveCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessData(e);

if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
}

我的尝试导致了这样的结果:

private async void StartReceive()
{
byte[] Buff = new byte[1024];
int recv = 0;
while (Socket.Connected)
{
recv = await NetworkStream.ReadAsync(Buff, 0, 1024);
ProcessData(Buff,recv);
}
}

我遇到的问题是调用 StartReceive() 的方法会阻塞,并且无法到达在StartReceive() 之后调用的随附的 StartSend() 方法。为StartReceive()创建一个新任务最终只会有 300 个左右的线程,而且它似乎只是通过调用StartReceive()` 来完成。

在使用 NetworkStream 时,在现有代码上实现新的 asyncawait 关键字的正确方法是什么,所以它正在使用Socket.SendAsync()Socket.ReceiveAsync() 正在使用线程池来避免拥有数百个线程/任务?

与使用 beginreceive 的 i/o 完成端口相比,以这种方式使用 networkstream 是否有任何性能优势?

最佳答案

您在这里同时更改了两件事:异步样式(SocketAsyncEventArgsTask/async)和抽象级别 ( SocketNetworkStream)。

既然您已经习惯了Socket,我建议您只更改异步样式,并继续直接使用Socket 类。

Async CTP 没有给 Socket 任何 async 兼容的方法(这很奇怪;我认为它们被错误地遗漏了,将被添加到 .NET 中4.5).

如果您使用我的 AsyncEx library,创建您自己的 ReceiveAsyncTask 扩展方法(以及其他操作的类似包装器)并不难:

public static Task<int> ReceiveAsyncTask(this Socket socket,
byte[] buffer, int offset, int size)
{
return AsyncFactory<int>.FromApm(socket.BeginReceive, socket.EndReceive,
buffer, offset, size, SocketFlags.None);
}

一旦你这样做了,你的StartReceive就可以这样写了:

private async Task StartReceive()
{
try
{
var buffer = new byte[1024];
while (true)
{
var bytesReceived = await socket.ReceiveAsyncTask(buffer, 0, 1024)
.ConfigureAwait(false);
ProcessData(buffer, bytesReceived);
}
}
catch (Exception ex)
{
// Handle errors here
}
}

现在,要解决许多小问题:

  • await 不会生成新线程。我写了an async/await intro on my blog ,和许多其他人一样。 async/await 允许并发,但这并不一定意味着多线程。
  • 数百个线程 可能会出现问题。不过,数百个任务根本不是问题;线程池和 BCL 旨在处理许多任务。
  • async/await 并不是一种全新的异步处理形式;这只是一种更简单的方式表达异步处理。它仍然在底层使用 IOCP。 async/await 的性能略低于低级方法;它的吸引力在于易于编写和组合异步方法。
  • 当切换到async/await 时,一个非常繁忙的系统会发现 GC 压力有所增加。并行团队的 Stephen Toub wrote up some example socket-specific awaitables这可以帮助解决这个问题。 (我建议首先使用简单的模式,只有在您认为有必要时才使用性能增强的方法;不过,如果您最终需要它,最好知道它就在那里)。
  • 异步方法应该返回 Task,除非您真的需要它们返回 voidTask 是可等待的,因此您的方法是可组合的(并且更容易测试); void 更像是“即发即忘”。
  • 您可以调用 ConfigureAwait(false) 来告诉 async 方法的其余部分在线程池线程上执行。我在上面的示例中使用了它,以便 ProcessData 在线程池线程中执行,就像使用 SocketAsyncEventArgs 时一样。
  • Socket.Connected 没用。 You need to send data to detect if the connection is still valid.

关于c# - 将 Socket.ReceiveAsync 替换为 NetworkStream.ReadAsync(可等待),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9733292/

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