Socket.EndReceive(...)不正确返回

问题描述:

我想使用Socket.BeginReceive(...)和Socket.EndReceive(...)作为我的UDP数据包接收器客户端。它按预期的方式接收和处理数据包,但是,当我希望取消和关闭套接字时,我实现的Close()函数在Socket.EndReceive(...)上退出。我假设线程抛出异常,但我无法弄清楚如何捕捉异常以查看问题所在。我之前使用Socket.EndReceive(...),SocketError作为成功返回。这是一段代码,显示了我如何使用套接字。Socket.EndReceive(...)不正确返回

更新的代码

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(异步编程模型)是错误的。请参阅:http://msdn.microsoft.com/en-us/library/ms228963.aspx

每个对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(); 
} 
+0

由于这是有道理的,虽然我每次配对与结束开始的时候还是有问题。我发布了更新以显示我的新更新。 – galford13x

+0

你不能多次调用EndReceive。在close方法中,您可以调用EndReceive以及回调函数。这有冲突。如果你想在你的close方法中等待当前的请求完成,那么你可以使用_recieveResult中的WaitHandle等待 – Polity

+0

确实我明白你的意思了。我在Stop函数中删除了EndReceive。问题在于,当我关闭套接字时,客户端总是会假设更多的数据将以这样的方式来处理,messageProcessor会执行并在尝试执行EndReceive时抛出ObjectDisposedException。出于某种原因,这似乎不是一个正确的关机。 – galford13x