发送消息后客户端停止工作,服务器不等待多个数据到来
Posted
技术标签:
【中文标题】发送消息后客户端停止工作,服务器不等待多个数据到来【英文标题】:Client stops working after sending message and server doesn't wait for mutliple data to come 【发布时间】:2021-12-06 18:47:03 【问题描述】:我最近开始学习计算机网络并决定尝试 TCP/IP 服务器和客户端。它们都可以工作,但是我在向服务器发送多个数据时遇到了问题。我使它看起来像客户端之间的聊天服务,但服务器只接受一个客户端并在发送数据后关闭连接,并且客户端在向服务器发送数据后由于某种原因停止响应(我认为问题来自服务器而不是客户端本身),没有错误消息,仅在我强制关闭客户端时在服务器端。 这就是我的服务器的样子...
static void Main(string[] args)
//User can define port
Console.WriteLine("open a port:");
string userInputPort = Console.ReadLine();
//listening for connections
TcpListener listener = new TcpListener(System.Net.IPAddress.Any, Convert.ToInt32(userInputPort));
listener.Start();
Console.WriteLine("listening...");
while (true)
//waiting for client to connect to server
Console.WriteLine("Waiting for connection...");
//when user connects to server, server will accept any request
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client Accepted");
NetworkStream stream = client.GetStream();
StreamReader streamR = new StreamReader(client.GetStream());
StreamWriter streamW = new StreamWriter(client.GetStream());
while (true)
if(client.Connected)
if (stream.CanRead)
//buffer
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
int recv = 0;
foreach (byte b in buffer)
if(b != 0)
recv++;
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request recived: " + request);
streamW.Flush();
这就是客户端的样子……
...
try
//try to connect
client = new TcpClient(textBoxIP.Text, Convert.ToInt32(textBoxPort.Text));
...
static void sendMessage(string message, TcpClient client)
int byteCount = Encoding.ASCII.GetByteCount(message);
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
stream.Write(sendData, 0, sendData.Length);
StreamReader streamReader = new StreamReader(stream);
string respone = streamReader.ReadLine();
stream.Close();
client.Close();
就像我说的,我还在学习计算机网络,对此代码的任何评论都会有所帮助! 谢谢
【问题讨论】:
因此,当您调试每个专业、行和状态时。你得到了什么结果,程序与你的期望有什么不同?如果你不能回答这个问题,那么你在调试代码方面做得还不够。编写复杂软件时需要掌握事实,需要确定它的运行方式,猜测会以失败告终,以及在***上无法回答的问题 【参考方案1】:如果您对自己正在编写的代码的实际期望有所了解,这会有所帮助。在我看来,你做了很多自动假设,但实际上并没有确保将它们放入你的代码中。
-
您的服务器最多只能接受一个客户端。不是一次一位客户,而是一位永远。你永远不会退出你的阅读循环,所以在客户端断开连接后,你最终会进入一个美妙的无限忙碌循环。您的意图可能是在另一个客户断开连接时为其提供服务,但这不是您正在做的事情。
您假设服务器将向客户端发送响应。但是您实际上从未发送任何响应!为了让客户端读取某些内容,服务器首先必须发送一些内容供客户端读取。
您假设客户端发送的字符串将以零结尾,或者
Read
的目标缓冲区将为零。如果您想要零终止,您必须自己从客户端发送 - StreamWriter
当然 不会这样做。 规则 字符串不是以零结尾的——它只是一种在内存中表示字符串的 C 风格的方式。你不应该假设缓冲区的内容超出Read
的返回值告诉你的返回值。
大概是你忘记放入的东西的问题。现在谈谈关于 TCP 工作原理的部分错误假设。为了清楚起见,我将告诉它是的方式,而不是错误的假设。
-
单次写入可能会导致另一侧的多次读取,而单次读取可以从另一侧的多次写入中读取数据。 TCP 不发送(和接收)消息,它处理流。如果流对您来说不够好,您需要在此基础上添加消息传递协议。
Read
返回读取了多少字节。使用它来处理响应,而不是寻找零。当Read
返回零时,表示连接已关闭,您也应该关闭您的身边。这就是您所需要的,而不是所有while (true)
、if (Connected)
和if (CanRead)
- 循环直到Read
返回零。处理收到的数据。
TCP 流比大多数流更难处理。它的行为完全不同,以至于使用像 StreamReader
这样的助手是危险的。您必须自己完成这项工作,或者获得一个更高抽象的库来处理网络。 TCP 是非常低级别。
您不能指望得到对Read
的回复。 TCP 使用连接,但它不会做任何事情来让连接保持活跃,或者在它关闭时通知它 - 它是为与今天非常不同的互联网设计的,它可以愉快地在服务中断数小时内幸存下来 - 因为只要你不尝试发送任何东西。如果客户端突然断开连接,服务器可能永远不会知道。
您还应该确保正确清理所有本机资源 - 尽可能使用using
确实很有帮助。 .NET最终会清理干净,但对于 I/O 之类的事情,这通常很危险。
【讨论】:
【参考方案2】: while (true)
if(client.Connected)
if (stream.CanRead)
如果client.Connected
或stream.CanRead
变为假,我没有看到任何代码退出外部while 循环。因此,当客户端断开连接并且它们变为假时,在我看来,服务器只是永远循环。
您至少应该进行所有错误处理(关闭所有必要的流)并跳出循环。
作为下一个问题,您的代码一次只能有一个客户端。如果客户端实际上没有关闭连接。我不确定正确的 C# 解决方案是什么,但我认为它为每个连接的客户端生成了一个单独的线程。
【讨论】:
以上是关于发送消息后客户端停止工作,服务器不等待多个数据到来的主要内容,如果未能解决你的问题,请参考以下文章