TcpClient:如何关闭并重新连接它?

TcpClient: How do I close and reconnect it again?

您好,感谢您的帮助。 这次想问一下TcpClient。 我有一个服务器程序,我正在编写一个客户端程序。 此客户端使用 TcpClient。首先创建一个新客户端

clientSocket=new TcpClient(); 

(顺便说一下,这会导致异常吗?以防万一我把它放在 try-catch 中,但我不确定这是否真的有必要) 无论如何,稍后我进入一个循环并在这个循环内连接到服务器

clientSocket.Connect("xx.xx.xx.xx",port);

然后我用

创建一个 NetworkStream
clientStream=clientSocket.GetStream();

然后开始通过Read等待服务器的数据。我知道这是阻塞的,所以我还设置了一个 ReadTimeOut(比如 1 秒)

无论如何,到目前为止一切顺利。 稍后如果我没有从服务器收到任何东西,我会尝试向它发送一些东西。如果这种情况持续发生 3 次,我 想关闭连接并重新连接到服务器

(请注意,一个完全不同的问题是当服务器以某种方式关闭时,导致客户端出现其他类型的错误 - 也许我稍后会问这个问题)

那么,我该怎么办?

 if(clientSocket.Connected)
            {
                Console.WriteLine("Closing the socket");
                clientSocket.Close();
            }

我关闭套接字。 循环结束,所以我再次回到开头并尝试连接到服务器。

clientSocket.Connect("xx.xx.xx.xx",port);

但是这会导致错误(实际上是未处理的异常)"Can not access a disposed object"

所以我的问题是我怎样才能关闭并重新连接到服务器?

再次感谢您的帮助

一个TcpClient实例只能用于连接一次。您可以简单地实例化一个新的 TcpClient,而不是尝试重新打开一个关闭的

中所述,一个 TcpClient 对象只能连接一次。如果你想重新连接到服务器,你必须创建一个新的 TcpClient 对象并再次调用 Connect()

也就是说,您的问题中存在一些明显的误解:

  1. 首先也是最重要的一点是,如果您打算再次使用 TcpClient 对象,则不应使用 ReceiveTimeout,例如向服务器发送一些数据。一旦超时时间过期,底层套接字就不再可用。

    如果你想在服务器还没有给你发送数据的时候周期性地向服务器发送数据,你应该使用异步I/O(无论如何你都应该这样做,尽管有学习曲线)并使用常规计时器对象来跟踪自从你从服务器接收数据以来已经过了多长时间。
  2. TcpClient 构造函数当然可以抛出异常。至少,任何 尝试 new 引用类型对象都可能抛出 OutOfMemoryException,而在 TcpClient 的情况下,它最终会尝试创建一个本机套接字句柄,这也可能会失败。

    虽然所有 I/O 对象和方法都可以抛出异常,但您应该只捕获您有办法妥善处理的异常。因此,在将 try/catch 块添加到代码之前,请确定在出现异常的情况下要做什么,以确保您的代码不会损坏任何数据并继续正确操作。通常不可能优雅地处理 OutOfMemoryException(并且在任何情况下保护 new 的所有使用都是不切实际的),但您当然可以捕获 SocketException,这可能会被构造函数抛出。如果抛出该异常,您应该立即放弃创建和使用 TcpClient 的尝试,并向用户报告错误,以便他们可以尝试更正阻止创建套接字的任何问题。
  3. 如果您的服务器应该向您发送数据,但您没有收到,那么关闭连接并重试不太可能改善这种情况。这只会给服务器造成额外的负载,使其更有可能无法响应。同样一遍又一遍地发送相同的数据。您应该将请求 一次 ,尽可能等待服务器的响应,如果您在期望的时间内没有得到响应,请向用户报告错误并让他们决定下一步做什么。

    请注意,在这种情况下,您 可以 使用 ReceiveTimeout 属性,因为您如果你没有及时得到回应,你要做的就是放弃连接,这很好。

很简单:

client.Close();
client = new TcpClient();
client.Connect(host, port);