从封闭的NetworkStream中读取不会导致任何exception

我正在尝试创建一个相当简单的客户端 – 服务器应用程序,但对于通信我想使用二进制序列化对象。 通信本身似乎相当不错,但是当我在客户端关闭流时,服务器并没有真正注意到它并继续尝试读取流。

服务器端(类Server,在单独的线程中执行):

听取联系

listener = new TcpListener(IPAddress.Parse("127.0.0.1"), this.Port); listener.Start(); while (!interrupted) { Console.WriteLine("Waiting for client"); TcpClient client = listener.AcceptTcpClient(); AddClient(client); Console.WriteLine("Client connected"); } 

添加客户端:

  public void AddClient(TcpClient socket) { Client client = new Client(this, socket); this.clients.Add(client); client.Start(); } 

监听消息(深入Client类):

 BinaryFormatter deserializer = new BinaryFormatter(); while (!interrupted) { System.Diagnostics.Debug.WriteLine("Waiting for the message..."); AbstractMessage msg = (AbstractMessage)deserializer.Deserialize(stream); System.Diagnostics.Debug.WriteLine("Message arrived: " + msg.GetType()); raiseEvent(msg); } 

unit testing:

 Server server = new Server(6666); server.Start(); Thread.Sleep(500); TcpClient client = new TcpClient("127.0.0.1", 6666); var message = new IntroductionMessage(); byte[] arr = message.Serialize(); client.GetStream().Write(arr, 0, arr.Length); Thread.Sleep(500); Assert.AreEqual(1, server.Clients.Count); client.GetStream().Close(); client.Close(); Thread.Sleep(1000); Assert.AreEqual(0, server.Clients.Count); server.Stop(); 

所以消息被正确读取,但是当我关闭流时,deserializer.Deserialize(stream)似乎没有抛出任何exception…所以它应该不是这样读的,或者我应该关闭客户端另一种方式?

假设服务器中用于反序列化消息的流是NetworkStream (这是TcpClient.GetStream()返回的流的类型),您应该做两件事:

  1. 为“连接结束”定义特定消息。 当服务器接收并反序列化此消息时,退出while循环。 为了使这项工作,客户端显然需要在关闭其TcpClient连接之前发送此类消息。 (您可以选择以类似方式工作的不同机制 – 但为什么不使用您已有的消息机制……)

  2. NetworkStream上设置ReadTimeout ,因此如果连接丢失且客户端无法发送“连接结束”消息,服务器将达到超时并意识到客户端“已死”。

服务器中用于侦听客户端消息的代码应类似于:

 // // Time-out after 1 minute after receiving last message // stream.ReadTimeOut = 60 * 1000; BinaryFormatter deserializer = new BinaryFormatter(); try { while (!interrupted) { System.Diagnostics.Debug.WriteLine("Waiting for the message..."); AbstractMessage msg = (AbstractMessage)deserializer.Deserialize(stream); System.Diagnostics.Debug.WriteLine("Message arrived: " + msg.GetType()); // // Exit while-loop when receiving a "Connection ends" message. // Adapt this if condition to whatever is appropriate for // your AbstractMessage type. // if (msg == ConnectionEndsMessage) break; raiseEvent(msg); } } catch (IOException ex) { ... handle timeout and other IOExceptions here... }