我正在尝试创建一个相当简单的客户端 - 服务器应用程序,但对于通信,我想使用二进制序列化对象。通信本身似乎相当不错,但是当我在客户端关闭流时,服务器并没有真正注意到它并继续尝试读取流。
服务器端(类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);
}
单元测试:
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)似乎没有抛出任何异常......所以它应该不是这样读的,还是我应该关闭客户以不同的方式?
答案 0 :(得分:0)
假设服务器中用于反序列化消息的流是NetworkStream(这是 TcpClient.GetStream()返回的流的类型),你应该做两件事:
为“连接结束”定义特定消息。当服务器接收并反序列化此消息时,退出while循环。为了使这项工作,客户端显然需要在关闭其TcpClient连接之前发送此类消息。 (您可以选择以类似方式工作的不同机制 - 但为什么不使用您已有的消息机制......)
在 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...
}