2013-03-19 48 views
1

我正在尋找一些關閉關閉套接字的幫助。我遇到的問題是,當我在Close()之前撥打Shutdown()時,這兩個調用中的一個似乎觸發了接收到的最後一個數據的套接字上的假讀取。我該如何阻止?關閉入站套接字導致舊數據被重新讀取

我的應用程序有兩對插座,就像FTP。一個是連接到遠程服務器的客戶端,另一個是監聽並接受來自遠程主機的第二個連接的服務器。此入站連接連接到異步OnReceived以處理來自遠程主機的未經請求的數據。

這一切工作正常,兩個插座可以保持連接數天或數週。但是如果出現問題,我會通過關閉所有內容並重新開始。在調用inboundSocket.Shutdown()inbounSocket.Close()(不知道哪一個很難在第二個線程中調試)期間,就好像我正在重新讀入入站套接字上的最後一個inboudn數據包。這會導致更多的問題。

我該如何關機。關閉,斷開等等,而不強迫重新讀取?

下面的示例代碼,剝離顯示的基本內容。

在此先感謝。

丹尼爾

public class TcpIpSenderReceiver 
{ 
    /// <summary> 
    /// Main thread, main entry point 
    /// </summary> 
    public void ConnectAndLogonAndStartReceivingInboundMessages() 
    { 
     CreateListenerAndStartListening(); 
     AcceptInboundSocketAndHookUpDataReceiptCallBack();   
    } 

    /// <summary> 
    /// Main thread 
    /// </summary> 
    int CreateListenerAndStartListening() 
    { 
     tcpListener = new TcpListener(LocalBoundIpAddress, listeningPort); 
     tcpListener.Start();   
    } 


    /// <summary> 
    /// SECOND thread 
    /// </summary> 
    void AcceptInboundSocketAndHookUpDataReceiptCallBack() 
    { 
     int i = 0; 
     while (i < 100 && !tcpListener.Pending()) 
     { 
      i++; 
      Thread.Sleep(100); 
     } 
     inboundSocket = tcpListener.AcceptSocket(); 
     bufferForReceive = new byte[bufferSize]; 
     WireUpCallbackForAsynchReceive(); 
    } 

    /// <summary> 
    /// SECOND thread 
    /// </summary> 
    void WireUpCallbackForAsynchReceive() 
    { 
     if (asynchCallbackFunctionForReceive == null) 
     { 
      asynchCallbackFunctionForReceive = new AsyncCallback(OnDataReceived); 
     } 
     if (inboundSocket.Connected) 
     { 
      try 
      { 
       asyncResultForReceive = inboundSocket.BeginReceive(bufferForReceive, 0, bufferForReceive.Length, SocketFlags.None, asynchCallbackFunctionForReceive, null); 
      } 
      catch (Exception) 
      { 
       //... 
      } 
     } 
    } 


    /// <summary> 
    /// SECOND thread 
    /// </summary> 
    void OnDataReceived(IAsyncResult asyn) 
    { 
     // Read data call goes here..... 

     if (asyncResultForReceive != null) 
     { 
      inboundSocket.EndReceive(asyncResultForReceive); 
     } 
     WireUpCallbackForAsynchReceive(); // listen again for next inbound message 
    } 


    void Shutdown() 
    { 
     shouldAbortThread = true; 
     asyncResultForReceive = null; 
     asynchCallbackFunctionForReceive = null; 
     if (outboundStreamWriter != null) 
     { 
      try 
      { 
       outboundStreamWriter.Close(); 
       outboundStreamWriter.Dispose(); 
       outboundStreamWriter = null; 
      } 
      finally { } 
     } 
     if (outboundNetworkStream != null) 
     { 
      try 
      { 
       outboundNetworkStream.Close(); 
       outboundNetworkStream.Dispose(); 
       outboundNetworkStream = null; 
      } 
      finally { } 
     } 
     if (tcpClient != null) 
     { 
      try 
      { 
       tcpClient.Close(); 
       tcpClient = null; 
      } 
      catch (SocketException) 
      { 
       // ... 
      } 
     } 
     if (inboundSocket != null) 
     { 
      try 
      { 
       // I think this is where it's puking 
       inboundSocket.Shutdown(SocketShutdown.Both); 
       inboundSocket.Close(); 
       inboundSocket = null; 
      } 
      catch (SocketException) 
      { 
       //... 
      } 
     } 
     if (tcpListener != null) 
     { 
      try 
      { 
       tcpListener.Stop(); 
       tcpListener = null; 
      } 
      catch (SocketException) 
      { 
       //... 
      } 
     } 
    } 


    #region Local variables 

    volatile bool shouldAbortThread; 
    TcpListener tcpListener; 
    TcpClient tcpClient; 
    StreamWriter outboundStreamWriter; 
    NetworkStream outboundNetworkStream; 
    Socket inboundSocket = null; 
    IAsyncResult asyncResultForReceive; 
    public AsyncCallback asynchCallbackFunctionForReceive; 
    byte[] bufferForReceive; 
    static string HostnameShared; 
    #endregion 
} 
+1

假設套接字是越野車的基本功能通常是錯的... ** **你的代碼是壞了,不是他們的。 – usr 2013-03-19 16:03:42

回答

0

我解決了這個問題,如下所示。我沒有提供回調函數並讓框架處理第二個線程,而是明確地啓動了我自己的工作線程並讓它阻塞,直到收到數據。如果收到零字節,我知道另一端正在關閉,可以很好地終止我的結局。我想分享的唯一問題是我需要嘗試捕獲阻塞的socket.Receive()函數並處理SocketError.Interrupted異常。當主程序終止時會發生這種情況。

代碼看起來有點像這樣:

 Thread dataReceivedWorkerThread; 

    void AcceptInboundSocketAndStartWorkerThread() 
    {    
     inboundSocket = tcpListener.AcceptSocket(); 
     dataReceivedWorkerThread = new Thread(new ThreadStart(ListenForAndWaitToReceiveInboundData)); 
     dataReceivedWorkerThread.Start(); 
    } 

    void ListenForAndWaitToReceiveInboundData() 
    { 
      var bytesRead = 0; 
      try 
      { 
       bytesRead = inboundSocket.Receive(bufferForReceive, 0, bufferForReceive.Length, SocketFlags.None); // blocks here     
      } 
      catch (SocketException se) 
      { 
       if (se.SocketErrorCode == SocketError.Interrupted) 
       { 
        // Handle shutdown by (e.g.) parent thread....      
       } 
       else 
       { 
        // handle other 
       } 
       return; 
      } 
      if (bytesRead == 0) 
      { 
       // handle shutdown from other end 
       return; 
      } 

      // Do stuff with received data.... 
     } 
    } 
1

OnDataReceived看起來(從評論,你忽略的EndReceive返回值的事實),你就已經inboundSocket稱爲EndReceive前處理在緩衝區中的數據。如果是這種情況,則沒有指示實際從套接字讀取的字節數(如果套接字正在關閉,則可能爲0),因此您正在處理仍在緩衝區中的數據以前的閱讀,因此重新閱讀舊數據的外觀。

您需要在嘗試處理任何數據之前致電EndReceive。喜歡的東西:

void OnDataReceived(IAsyncResult asyn) 
{ 
    var bytesRead = inboundSocket.EndReceive(asyn); 
    if (bytesRead == 0) return; // Socket is closed 

    // Process the data here 

    WireUpCallbackForAsynchReceive(); // listen again for next inbound message 
} 

而且,事實上,你不檢查的EndReceive返回值表明你希望每一個接收到返回選擇對整個緩衝區的數據的價值,或者也許是相同的字節數就像服務器在撥打電話Send/BeginSend時發送的那樣,情況並非總是如此。

+0

銥,是的,沒錯,我正在閱讀和處理EndReceive之前的數據。非常感謝您的明確解釋,我會試一試。 – 2013-03-22 13:19:54

相關問題