Jos*_*osh 10 c# sockets asynchronous networkstream async-await
我有一个应用程序,它同时生成几百个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); }
}
Run Code Online (Sandbox Code Playgroud)
我的尝试导致了这样的事情:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是方法调用StartReceive()
会阻塞,而不是到达随附的StartSend() method called after
StartReceive(). Creating a new task for
StartReceive()would just end up with 300-ish threads, and it seems to do so just by calling
StartReceive()`.
在使用a时,在我的现有代码上实现new async
和await
关键字的正确方法是什么?NetworkStream
使用线程池Socket.SendAsync()
并且Socket.ReceiveAsync()
正在使用以避免必须拥有数百个线程/任务?
networkstream
以这种方式使用i/o完成端口是否有任何性能优势beginreceive
?
Ste*_*ary 25
你在这里一次改变两件事:异步样式(SocketAsyncEventArgs
到Task
/ async
)和抽象层次(Socket
to NetworkStream
).
由于您已经习惯了Socket
,我建议只更改异步样式,并继续Socket
直接使用该类.
Async CTP没有提供Socket
任何async
兼容的方法(这很奇怪;我认为它们被误删了,将被添加到.NET 4.5中).
ReceiveAsyncTask
如果您使用我的AsyncEx库,那么创建自己的扩展方法(以及其他操作的类似包装器)并不难:
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);
}
Run Code Online (Sandbox Code Playgroud)
一旦你这样做,你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
}
}
Run Code Online (Sandbox Code Playgroud)
现在,要解决许多小问题:
await
不会产生新的线程.我和其他许多人一样,在我的博客上写了一篇async/await简介.async
/ await
允许并发,但这并不一定意味着多线程.async
/ await
不是一种全新的异步处理形式; 它只是一个简单的方法来表达异步处理.它仍然使用下面的IOCP. async
/的await
性能略低于低级方法; 它的吸引力在于编写和编写异步方法的简易性.async
/ 时会看到一些GC压力增加await
.并行团队的Stephen Toub 写了一些示例套接字特定的等待,可以帮助解决这个问题.(我建议首先使用简单的模式,如果你觉得有必要,只使用性能增强的方法;但是,如果最终需要它,最好知道它在那里).Task
除非你确实需要它们返回void
.Task
是等待的,所以你的方法是可组合的(更容易测试); void
更像是"火与忘".ConfigureAwait(false)
告诉其余async
方法在线程池线程上执行.我在上面的例子中使用它,因此它ProcessData
在线程池线程中执行,就像使用时一样SocketAsyncEventArgs
.Socket.Connected
没用.您需要发送数据以检测连接是否仍然有效.