异步/等待套接字连接中的竞争条件

时间:2015-03-18 14:07:54

标签: c# sockets async-await

此send方法将定期失败,因为控制权返回给调用线程,并且在套接字打开时再次调用Send

我正在使用Stephen Toub的课程: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的调用不止一次。

1 个答案:

答案 0 :(得分:2)

应该等待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();
相关问题