【问题标题】:Reconnecting TCPClient throws exception重新连接 TCPClient 引发异常
【发布时间】:2014-01-08 14:58:11
【问题描述】:

我正在连接到 Socket 服务器以发送和接收消息。当消息进出时一切正常,但每隔一段时间就会失去连接。我试图捕捉异常并重新连接到服务器。 失去连接时的第一个异常:

System.IO.IOException:无法从传输连接读取数据:已建立的连接被主机中的软件中止。 ---> System.Net.Sockets.SocketException:已建立的连接被主机中的软件中止 在 System.Net.Sockets.Socket.Receive(Byte[] 缓冲区,Int32 偏移量,Int32 大小,SocketFlags socketFlags) 在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 大小)

然后当它尝试重新连接时:

System.ObjectDisposedException:无法访问已处置的对象。 对象名称:“System.Net.Sockets.NetworkStream”。 在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 大小)

我的问题是我做错了什么?重新连接到服务器的最佳解决方案是什么? 我的代码如下所示:

  class Test
        {
            private TcpClient myTcpClient;
            private NetworkStream myStream;
            private string host = xxx.xxx.xxx;
            private int port = 8888;
            private string streaming = "";

        public void Listen()
        {
            this.myTcpClient = new TcpClient(host, port);
            this.myStream = this.myTcpClient.GetStream();
            Listener();
        }

        private void Listener()
        {
            try
            {
                while (true)
                {
                    byte[] numResponse = new byte[8192];
                    int x = this.myStream.Read(numResponse, 0, numResponse.Length);
                    Decrypt(numResponse, 0, x);
                    string stream = Encoding.UTF8.GetString(numResponse);
                    this.streaming = string.Concat(this.streaming, stream);
                }
            }
            catch(Excpetion ex)
            {
                // write ex.ToString() to TextFile
                this.myTcpClient = new TcpClient(host, port);
                this.myStream = this.myTcpClient.GetStream();
                Listener();
            }
        }
    }

【问题讨论】:

  • 不相关,但您没有使用 myStream.Read 的返回值。这始终是一个错误。使用 StreamReader 从 NetworkStream 中读取。您的 Unicode 解码也被破坏了,因为数据包可能被任意拆分。

标签: c# .net wpf sockets tcp


【解决方案1】:

我认为您的异常是由于您在 catch 语句中执行重新初始化而引起的。

在 catch 内部时,网络流仍处于打开状态。因此,当您创建一个具有相同端口的新 TCP 客户端时,我猜它使用与以前相同的网络流,它在尝试读取时被锁定。

在catch里面,你可以试试

 this.myTcpClient.Close();
 this.myTcpClient.Dispose();
 this.myTcpClient = new TcpClient(host, port);
 this.myStream = this.myTcpClient.GetStream();

这可能行得通。但我建议不要在 catch 中这样做,因为您可能会导致另一个异常。我会说尝试阅读一些示例,因为此代码确实存在其他答案中提到的其他问题。

【讨论】:

    【解决方案2】:

    您不应该在 while(true) 循环中阅读。最好检查 myStream.Read 是否返回 0 字节或发生 TCP 相关异常,在这种情况下我认为连接将被关闭,您需要释放资源并重新连接。

    在这里你可以找到安全的阅读方法-http://www.yoda.arachsys.com/csharp/readbinary.html

    【讨论】:

      【解决方案3】:

      这里有一些可能有帮助的代码

      // State object for receiving data from remote device.
      public class StateObject
      {
          /// <summary>
          /// Client socket.
          /// </summary>
          public Socket workSocket = null;
      
          /// <summary>
          /// Size of receive buffer.
          /// </summary>
          public const int BufferSize = 256;
      
          /// <summary>
          /// Receive buffer.
          /// </summary>
          public byte[] buffer = new byte[BufferSize];
      
          /// <summary>
          /// Received data string.
          /// </summary>
          public StringBuilder sb = new StringBuilder();
      }
      
      public class AsynchronousClient
      {
          // The port number for the remote device.
          private const int _port = xxxx;
          private const string _address = "xx.xx.xx.xx";
      
          // ManualResetEvent instances signal completion.
          private static ManualResetEvent _connectDone = new ManualResetEvent(false);
          private static ManualResetEvent _sendDone = new ManualResetEvent(false);
          private static ManualResetEvent _receiveDone = new ManualResetEvent(false);
      
          private static string _response = string.Empty;
      
          public static void StartClient(string data)
          {
              // Connect to a remote device.
              try
              {
                  var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      
                  // Connect to the remote endpoint.
                  client.BeginConnect(_address, _port, ConnectCallback, client);
                  _connectDone.WaitOne();
      
                  // Send test data to the remote device.
                  //Console.WriteLine("Sending data : {0}", data);
                  Send(client, "US\r\n");
                  _sendDone.WaitOne();
      
      
                  Thread.Sleep(1000);
                  Send(client, data);
                  _sendDone.WaitOne();
      
      
                  // Receive the response from the remote device.                
                  Receive(client);
                  _receiveDone.WaitOne();
      
                  // Write the response to the console.
                  //Console.WriteLine("Response received : {0}", _response);
      
                  // Release the socket.
                  client.Shutdown(SocketShutdown.Both);
                  client.Close();
      
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      
          private static void ConnectCallback(IAsyncResult ar)
          {
              try
              {
                  // Retrieve the socket from the state object.
                  var client = (Socket)ar.AsyncState;
      
                  // Complete the connection.
                  client.EndConnect(ar);
      
                  Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
      
                  // Signal that the connection has been made.
                  _connectDone.Set();
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      
          private static void Receive(Socket client)
          {
              try
              {
                  // Create the state object.
                  var state = new StateObject();
                  state.workSocket = client;
      
                  // Begin receiving the data from the remote device.
                  client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state);
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      
          private static void ReceiveCallback(IAsyncResult ar)
          {
              try
              {
                  // Retrieve the state object and the client socket 
                  // from the asynchronous state object.
                  var state = (StateObject)ar.AsyncState;
                  var client = state.workSocket;
      
                  int bytesRead = client.EndReceive(ar);
                  if (bytesRead > 0)
                  {
                      state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                      client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state);
                  }
                  else
                  {
                      // All the data has arrived; put it in response.
                      if (state.sb.Length > 1) _response = state.sb.ToString();                    
                      _receiveDone.Set();
                  }
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      
          private static void Send(Socket client, String data)
          {            
              var byteData = Encoding.ASCII.GetBytes(data);
              client.BeginSend(byteData, 0, byteData.Length, 0, SendCallback, client);
          }
      
          private static void SendCallback(IAsyncResult ar)
          {
              try
              {
                  var client = (Socket)ar.AsyncState;
      
                  var bytesSent = client.EndSend(ar);                
                  Console.WriteLine("Sent {0} bytes to server.", bytesSent);                
                  _sendDone.Set();
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.ToString());
              }
          }
      }
      

      【讨论】:

      • 这段代码是基于socket的,而作者尝试使用TcpClient。
      • same..tcpclient 不只是套接字的包装器吗?
      • 它是一个包装器。但是作者试图找出他的代码中的一个问题,而不是寻求新的解决方案
      • 您提供的代码也无法处理重新连接并在接收后关闭连接
      猜你喜欢
      • 2011-09-05
      • 2015-08-27
      • 2011-08-20
      • 2020-11-26
      • 2012-01-13
      • 2020-10-29
      • 1970-01-01
      • 2011-09-12
      • 2017-01-17
      相关资源
      最近更新 更多