客户端发送消息后停止工作,服务器不等待多个数据到来
Client stops working after sending message and server doesn't wait for mutliple data to come
我最近开始学习计算机网络,并决定尝试 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();
}
正如我所说,我仍在学习计算机网络,对此代码的任何评论都会有所帮助!
谢谢
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
我没有看到任何代码,如果 client.Connected
或 stream.CanRead
变为假,则退出外部 while 循环。所以,当客户端断开连接并且它们变为假时,在我看来服务器只是永远循环。
您至少应该进行所有错误处理(关闭所有必要的流)并跳出循环。
作为下一个问题,您的代码一次只能有一个客户端。如果客户端实际上没有关闭连接。我不确定正确的 C# 解决方案是什么,但我认为它为每个连接的客户端生成一个单独的线程。
如果您让自己了解您对所编写的代码的实际期望,这会有所帮助。在我看来,您做出了很多自动假设,但实际上并没有确保将它们放入您的代码中。
- 您的服务器最多只能接受一个客户端。不是一个客户一次,而是一个曾经。你永远不会退出你的阅读循环,所以在客户端断开连接后,你将进入一个美妙的无限忙碌循环。您的意图可能是在一个断开连接时为另一个客户提供服务,但这不是您正在做的。
- 您假定服务器将向客户端发送响应。但是您实际上从未发送任何回复!客户端要读取内容,服务器首先必须发送内容供客户端读取。
- 您假设客户端发送的字符串将以零结尾,或者
Read
的目标缓冲区将被清零。如果你想要零终止,你必须自己从客户端发送它 - StreamWriter
当然 不会那样做。字符串不是作为 规则 以零终止的——它只是一种在内存中表示字符串的 C 风格方式。你不应该假设缓冲区的内容 beyond 什么 Read
的 return 值告诉你是 returned.
这些可能是您忘记完全放入的问题。现在谈谈对 TCP 部分工作原理的错误假设。为清楚起见,我将说明 是 的方式,而不是不正确的假设。
- 单次写入可以导致另一侧多次读取,单次读取可以读取另一侧多次写入的数据。 TCP 不发送(和接收)消息,它处理流。如果流对您来说不够好,您需要在此基础上添加消息传递协议。
Read
returns 读取了多少字节。使用它来处理响应,而不是寻找零。当 Read
return 为零时,表示连接已关闭,您也应该关闭您的一侧。这就是您所需要的,而不是所有 while (true)
、if (Connected)
和 if (CanRead)
- 循环直到 Read
return 为零。处理您收到的数据。
- TCP 流比大多数流更难处理;它的行为非常不同,以至于使用像
StreamReader
这样的助手是危险的。您必须自己完成这项工作,或者获得更高抽象的库来处理网络。 TCP 非常 低级别。
- 您不能指望得到
Read
的回复。 TCP 使用连接,但它不会自己做任何事情来保持连接的活动,也不会在连接断开时发出通知——它是为与今天截然不同的互联网而设计的,它可以愉快地在服务中断数小时内幸存下来——因为只要您不尝试 发送 任何东西。如果客户端突然断开连接,服务器可能永远不会知道。
您还应该确保正确清理所有本机资源 - 尽可能使用 using
真的很有帮助。 .NET 最终会 清理,但对于 I/O 之类的东西,这通常会很危险。
我最近开始学习计算机网络,并决定尝试 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();
}
正如我所说,我仍在学习计算机网络,对此代码的任何评论都会有所帮助! 谢谢
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
我没有看到任何代码,如果 client.Connected
或 stream.CanRead
变为假,则退出外部 while 循环。所以,当客户端断开连接并且它们变为假时,在我看来服务器只是永远循环。
您至少应该进行所有错误处理(关闭所有必要的流)并跳出循环。
作为下一个问题,您的代码一次只能有一个客户端。如果客户端实际上没有关闭连接。我不确定正确的 C# 解决方案是什么,但我认为它为每个连接的客户端生成一个单独的线程。
如果您让自己了解您对所编写的代码的实际期望,这会有所帮助。在我看来,您做出了很多自动假设,但实际上并没有确保将它们放入您的代码中。
- 您的服务器最多只能接受一个客户端。不是一个客户一次,而是一个曾经。你永远不会退出你的阅读循环,所以在客户端断开连接后,你将进入一个美妙的无限忙碌循环。您的意图可能是在一个断开连接时为另一个客户提供服务,但这不是您正在做的。
- 您假定服务器将向客户端发送响应。但是您实际上从未发送任何回复!客户端要读取内容,服务器首先必须发送内容供客户端读取。
- 您假设客户端发送的字符串将以零结尾,或者
Read
的目标缓冲区将被清零。如果你想要零终止,你必须自己从客户端发送它 -StreamWriter
当然 不会那样做。字符串不是作为 规则 以零终止的——它只是一种在内存中表示字符串的 C 风格方式。你不应该假设缓冲区的内容 beyond 什么Read
的 return 值告诉你是 returned.
这些可能是您忘记完全放入的问题。现在谈谈对 TCP 部分工作原理的错误假设。为清楚起见,我将说明 是 的方式,而不是不正确的假设。
- 单次写入可以导致另一侧多次读取,单次读取可以读取另一侧多次写入的数据。 TCP 不发送(和接收)消息,它处理流。如果流对您来说不够好,您需要在此基础上添加消息传递协议。
Read
returns 读取了多少字节。使用它来处理响应,而不是寻找零。当Read
return 为零时,表示连接已关闭,您也应该关闭您的一侧。这就是您所需要的,而不是所有while (true)
、if (Connected)
和if (CanRead)
- 循环直到Read
return 为零。处理您收到的数据。- TCP 流比大多数流更难处理;它的行为非常不同,以至于使用像
StreamReader
这样的助手是危险的。您必须自己完成这项工作,或者获得更高抽象的库来处理网络。 TCP 非常 低级别。 - 您不能指望得到
Read
的回复。 TCP 使用连接,但它不会自己做任何事情来保持连接的活动,也不会在连接断开时发出通知——它是为与今天截然不同的互联网而设计的,它可以愉快地在服务中断数小时内幸存下来——因为只要您不尝试 发送 任何东西。如果客户端突然断开连接,服务器可能永远不会知道。
您还应该确保正确清理所有本机资源 - 尽可能使用 using
真的很有帮助。 .NET 最终会 清理,但对于 I/O 之类的东西,这通常会很危险。