具有多次等待的异步功能会导致问题

时间:2019-11-03 12:21:39

标签: c# .net-core async-await socketasynceventargs

在我的客户端应用中,每个客户端产生两个Socket,一个用于接收,另一个用于发送并以这种方式连接到服务器:

async void Connect2Server(object obj)
{
    recvArgs = new SocketAsyncEventArgs();
    sendArgs = new SocketAsyncEventArgs();
    recvArgs.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    sendArgs.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    await recvArgs.AcceptSocket.ConnectAsync(host, port);
    await recvArgs.AcceptSocket.SendAsync(Info<SockInfo>.Pack(new SockInfo()
    {
        Name = ClientName,
        RecvArg = true
    }), SocketFlags.None);

    await sendArgs.AcceptSocket.ConnectAsync(host, port);
    await sendArgs.AcceptSocket.SendAsync(Info<SockInfo>.Pack(new SockInfo()
    {
        Name = ClientName,
        RecvArg = false
    }), SocketFlags.None);

    SetBuffer(recvArgs, bufferSize);
    recvArgs.Completed += Receive;
    recvArgs.AcceptSocket.ReceiveAsync(recvArgs);
}

,并且在服务器的AcceptAsync回调中,我正在这样做:

void Accepted(object sender, SocketAsyncEventArgs e)
{
    e.Completed -= Accepted;
    e.Completed += CheckInfo;
    SetBuffer(e, infoBufferLength);
    e.AcceptSocket.ReceiveAsync(e);
    Accept();
}

服务器的CheckInfo函数检查客户端发送的SockInfo。如果RecvArg = true服务器将SocketAsyncEventArgs分配为其SendArgs,否则RecvArgs如下:

void CheckInfo(object sender, SocketAsyncEventArgs e)
{
    lock (Clients)
    {
        e.Completed -= CheckInfo;
        var info = Info<SockInfo>.Unpack(e.Buffer);
        Client c = Clients.FirstOrDefault(x => x.Name == info.Name);
        if (c == null)
        {
            c = new Client();
            c.Name = info.Name;
            Clients.Add(c);
        }

        if (info.RecvArg)
        {
            c.SendArgs = e;
            c.SendArgs.SetBuffer(null);
            c.SendArgs.Completed += Sent;
        }
        else
        {
            c.RecvArgs = e;
            SetBuffer(c.RecvArgs, bufferLength);
            c.RecvArgs.Completed += Received;
            c.RecvArgs.AcceptSocket.ReceiveAsync(c.RecvArgs);
        }
    }
}

ClientsObservableCollection中的Client

class Client
{
    public string Name { get; set; }
    public SocketAsyncEventArgs SendArgs { get; set; }
    public SocketAsyncEventArgs RecvArgs { get; set; }
}

SockInfo是具有以下属性的结构:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SockInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string Name;
    public bool RecvArg;       
}

如果我设置了三个断点:客户端应用程序Connect2Server函数的第二个和第四个await的第一个和第二个,服务器端CheckInfo的第三个和第二个,并以调试模式{{1 }}被击中两次,并且CheckInfo函数中的c.SendArgsc.RecvArgs都得到了CheckInfo。但是,如果我删除前两个断点,SocketAsyncEventArgs几乎总是被击中一次,而CheckInfo仍然是c.RecvArgs

为什么以及如何确保null始终获得其c.RecvArgs
另一个问题是我必须在SocketAsyncEventArgs的{​​{1}}上拥有lock吗?


编辑

另外两个功能可能与此问题(1)Clients有关,服务器开始监听并将控制权传递给(2)CheckInfo,每个创建一个全新的StartServer时间被称为。这是这两个:

Accept

1 个答案:

答案 0 :(得分:0)

我不知道为什么我必须手动调用这些pdb,但不确定是否可以解决。我要在df.map_partitions(GetID).compute(scheduler='single-threaded') %debug函数中进行一些更改,以下是那些更改:

callbacks

到目前为止,它与那些AcceptAccepted都可以正常工作!