此发送方法会定期失败,因为控制权返回到调用线程,并且在套接字打开时再次调用 Send
。
我正在使用 Stephen Toub 的类(class):http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx
这会导致异常:在已连接的套接字上发出连接请求。
确保异步方法不会遭受这种命运的正确方法是什么?基本上,在建立连接之前发送实际上无法完成。
public async Task Send(byte[] tosend)
{
// this code is not correct / not thread safe.
if (this.socket.Connected)
await this.StartSending(tosend);
else
await StartConnecting(tosend);
}
private async Task StartSending(byte[] tosend)
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(tosend, 0, tosend.Length);
var awaitable = new SocketAwaitable(args);
await this.socket.SendAsync(awaitable);
}
private async Task StartConnecting(byte[] tosend)
{
var local = Dns.GetHostEntry(Dns.GetHostName());
var ep = new IPEndPoint(local.AddressList.First(_ => _.AddressFamily == AddressFamily.InterNetwork), this.port);
var args = new SocketAsyncEventArgs() { RemoteEndPoint = ep };
var awaitable = new SocketAwaitable(args);
await this.socket.ConnectAsync(awaitable);
await StartSending(tosend);
}
我的测试只是非常快速地连续调用Send
。
var sends = arrays.Select(_ => writer.Send(_)).ToArray();
Task.WaitAll(sends);
有时上面的代码工作得很好,并且套接字已连接,socket.Connected
'按时'设置为 true。其他时候,对 this.socket.ConnectAsync
的调用会发生多次。
最佳答案
应该等待对 Send
的调用,这样您就可以知道连接已经建立,也可以知道数据正在按顺序发送。这最好通过 foreach
循环来处理,而不是 .Select
。
foreach (var data in arrays)
await writer.Send(data);
大概您创建了变量sends
,以便您可以对其进行Task.WhenAll
。不幸的是,由于您已经发现的原因,这不起作用。您可以使用名为 Connect
的单独方法来解决此问题,该方法异步连接到远程主机,但不发送数据。然后你可以这样做:
await writer.Connect();
var sends = arrays.Select(_ => writer.Send(_)).ToArray();
关于c# - 异步/等待套接字连接中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29124274/