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

C# 异步/等待套接字连接中的竞争条件,c#,sockets,async-await,C#,Sockets,Async Await,此发送方法将定期失败,因为控件返回到调用线程,并且在套接字打开时再次调用send 我正在使用Stephen Toub的课程: 这会导致异常:在已连接的套接字上发出连接请求。 确保异步方法不会遭受这种命运的正确方法是什么。基本上,在建立连接之前,发送实际上无法完成 public async Task Send(byte[] tosend) { // this code is not correct / not thread safe. if (thi

此发送方法将定期失败,因为控件返回到调用线程,并且在套接字打开时再次调用
send

我正在使用Stephen Toub的课程:

这会导致异常:在已连接的套接字上发出连接请求。
确保异步方法不会遭受这种命运的正确方法是什么。基本上,在建立连接之前,发送实际上无法完成

    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“on time”。其他时候,对
this.socket.ConnectAsync
的调用会发生多次。

应该等待对
Send
的调用,这样您就可以知道连接已经建立,也可以知道数据正在按顺序发送。这最好由
foreach
循环处理,而不是
。选择

foreach (var data in arrays)
    await writer.Send(data);
假设您创建变量
sends
,这样您就可以
Task.whalll
。不幸的是,由于您已经发现的原因,这将不起作用。您可以使用名为
Connect
的单独方法解决此问题,该方法异步连接到远程主机,但不发送数据。然后你可以做:

await writer.Connect();
var sends = arrays.Select(_ => writer.Send(_)).ToArray();

你能澄清一下“控制权被返回到调用线程吗?”当然,Send被调用,它反过来调用startConnection和ConnectAsync。然后调用下一个要发送的调用,该调用将StartConnection再次调用为socket。Connected仍然不是true。第一个连接成功,第二个连接抛出异常。例外情况是间歇性的。我必须运行几次测试来重现这个问题,因为有些时候套接字会及时打开。我对wait的理解是,它返回控制而不阻塞-这就是我所指的。谢谢,我仍然在努力理解异步模型。。。我认为应该更容易指定任务依赖关系,这基本上就是我在这里需要的。排序的延续。这是一个很好的例子,但这也会起作用:var sends=writer.Send(arrays.First()).ContinueWith(x=>Task.WaitAll(arrays.Skip(1)。Select(=>writer.Send()).ToArray()),cancellationTokenSource.Token);