2012-12-17 184 views
2

我想使用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(); 
} 

回答

3

您使用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