2013-03-19 13 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

相关问题