C# 套接字.EndReceive(…)未正确返回

C# 套接字.EndReceive(…)未正确返回,c#,.net,exception-handling,C#,.net,Exception Handling,我正在尝试使用Socket.BeginReceive(…)和Socket.EndReceive(…)作为UDP数据包接收器客户端。它按预期接收和处理数据包,但是,当我希望取消并关闭套接字时,我实现的Close()函数在socket.EndReceive(…)上退出。我假设线程上抛出了一个异常,但我不知道如何捕获该异常以查看问题所在。我以前使用过Socket.EndReceive(…),SocketError返回为Success。下面是一段代码,演示了如何使用套接字 更新代码 void _star

我正在尝试使用Socket.BeginReceive(…)和Socket.EndReceive(…)作为UDP数据包接收器客户端。它按预期接收和处理数据包,但是,当我希望取消并关闭套接字时,我实现的Close()函数在socket.EndReceive(…)上退出。我假设线程上抛出了一个异常,但我不知道如何捕获该异常以查看问题所在。我以前使用过Socket.EndReceive(…),SocketError返回为Success。下面是一段代码,演示了如何使用套接字

更新代码

void _startReceiving()
{
    _buffer = new byte[Marshal.SizeOf(typeof(EthernetShare.Message))];
    _receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, null);
}

private void messageProcessor(IAsyncResult result)
{
    int packetSize = _udpSocket.EndReceive(result);
    if (packetSize == _buffer.Length)
    {
        byte[] packet = _buffer;
        IAsyncResult asyncResult = result;
        _startReceiving();
        OnMessageReceieved(_buffer.ToStruct<DataStreamingMessage>());
    }
}
public void Stop()
{

    _continue = false;
    SocketError error;
    try
    {
        int tmp = _udpSocket.EndReceive(_receiveResult, out error);

    }
    catch (Exception)
    {

        throw;
    }
    _udpSocket.Close();
}
private Socket _udpSocket;
private byte[] _buffer;
private IAsyncResult _receiveResult;
void _startReceiving()
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(EthernetShare.Message))];
    _receiveResult = _udpSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, messageProcessor, null);
    //_receiveResult = _udpSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, messageProcessor, _continue);
}

private void messageProcessor(IAsyncResult result)
{

    //if ((bool)result.AsyncState && result.IsCompleted)
    if (result.IsCompleted)
    {
        _buffer = new byte[Marshal.SizeOf(typeof (EthernetShare.Message))];
        //_receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, _continue);
        _receiveResult = _udpSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, messageProcessor, null);
    }
}


public void Stop()
{

    _continue = false;
    SocketError error;
    try
    {
        int tmp = _udpSocket.EndReceive(_receiveResult, out error);

    }
    catch (Exception)
    {

        throw;
    }
    _udpSocket.Close();
}
您使用的APM(异步编程模型)是错误的。见:

对BeginXXX的每次调用都应与EndXXX匹配

在伪代码中,它可能如下所示:

private bool isClosed;
private Socket socket;

void BeginReceiveNextPacket(){
    socket.BeginReceive(..., EndReceiveNextPacket);
}

void EndReceiveNextPacket(IAsyncResult result){
    try{
        // By making a call to EndReceive, we allow the socket to wrap up, close internal handles and raise any exceptions if they exist.
        socket.EndReceive(result); 

        // Now make a new call to BeginReceive after we invoked the actual call to EndReceive.
        BeginReceiveNextPacket();
    }
    catch(SocketClosedException) {
        if (closed){
            // We forcefully closed this socket. Therefore, this exception was expected and we can ignore it.
        }
        else{
            throw; // Catch an unexpected exception.
        }
    }
}

void Stop(){
    isClosed = true;
    socekt.Close();
}

谢谢,这是有道理的,虽然我仍然有问题时,配对每一个开始与结束。我发布了一个更新以显示我的新更新。您不能有多个呼叫要结束接收。在close方法中,您可以调用EndReceive以及回调。这是一种冲突。如果您想在close方法中等待当前请求完成,那么可以使用_receiveResultinded中的WaitHandle等待,我明白您的意思。我删除了停止函数中的EndReceive。这就是问题所在,当我关闭套接字、messageProcessor执行以及尝试执行EndReceive时,客户机总是假设会有更多数据提交,并抛出ObjectDisposedException。由于某些原因,这似乎不是一个正确的关闭。当您关闭套接字时,挂起的接收可能会提前结束。您需要做的是在close函数中设置一个标志,指示您已关闭套接字。下一步,在接收回调中,只要未设置标志,就只执行工作(包括endreceive)。