TcpClient 不会接收所有数据

Posted

技术标签:

【中文标题】TcpClient 不会接收所有数据【英文标题】:TcpClient doesn't reveive all data 【发布时间】:2021-10-12 11:45:20 【问题描述】:

我有一个像这样工作的“信使”应用程序: 客户端向服务器发送消息 -> 服务器将消息转发给其余客户端 -> 客户端读取消息。

服务器始终接收消息,但客户端不接收。

将消息转发到所有客户端(Server/TcpListener)的代码:

public static void SendToAll(TcpClient sender, string message)

   // Log the recieved message in the console
   Console.WriteLine(message);

   // Save the recieved message for new clients
   messageLog += message + "\n";

   byte[] msg = Encoding.ASCII.GetBytes(message);
   foreach (TcpClient client in clients.Keys)
   
      if (client == sender || clients[client] == "") continue;
      if (!client.Connected)
      
         clients.Remove(client);
         continue;

      

      NetworkStream stream = client.GetStream();
      stream.Write(msg, 0, msg.Length);
   

从服务器读取消息的代码(TcpClient):

byte[] buffer = new byte[1024];
while (true)

   using (MemoryStream memoryStream = new MemoryStream())
   
      Int32 bytes = 0;
      do
      
         bytes = stream.Read(buffer, 0, buffer.Length);
         memoryStream.Write(buffer, 0, bytes);
      
      while (stream.DataAvailable);
      Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));

Server (image attached)

Client1 (image attached)

Client2 (image attached)

【问题讨论】:

foreach (TcpClient client in clients.Keys) - 呃,这段代码是否将 TcpClient 对象存储为字典键?如果是这样,你不应该这样做。 我怀疑您的问题是 DataAvailable 返回 false ,因为您的客户端已读取并处理所有可用数据,即使尚未全部到达,并且在准备好之前要求更多,然后在被告知“不可用”时放弃(因为下一个数据仍在传输中) 顺便说一句,使用 SignalR 或一些类似的抽象可能会让你的生活更简单 @Dai 我只是第一次摆弄 TCP,所以我还没有真正考虑到安全性、性能等。如果您可以选择更好的选择,那就太好了。 @CaiusJard 我尝试切换到此代码:Int32 bytesRead = stream.Read(buffer, 0, buffer.Length); string message = Encoding.ASCII.GetString(buffer, 0, bytesRead); Console.WriteLine(message); 还是一样 【参考方案1】:

找到答案了。

问题可能是因为 TCP 速度慢;读取所有流还没有完全完成,并且已经负责读取新数据。

所以我换了

byte[] buffer = new byte[1024];
while (true)

   using (MemoryStream memoryStream = new MemoryStream())
   
      Int32 bytes = 0;
      do
      
         bytes = stream.Read(buffer, 0, buffer.Length);
         memoryStream.Write(buffer, 0, bytes);
      
      while (stream.DataAvailable);
      Console.WriteLine(Encoding.ASCII.GetString(memoryStream.ToArray()));

// ... Main() 
while (true) StartRead();
// ... 

public static async void StartRead(NetworkStream stream)

    byte[] buffer = new byte[1024];
    Int32 bytesRead = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length));
    string message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
    Console.WriteLine(message);         

【讨论】:

以上是关于TcpClient 不会接收所有数据的主要内容,如果未能解决你的问题,请参考以下文章

在 websocket 上使用 TcpClient 接收数据得到 \0\0\0\0

如何处理 TCPClient 中接收到的数据? (德尔福 - 印地)

Socket入门笔记 用TcpClient实现一个简易聊天室

(16)C# TcpClient异步连接和接收数据的小例子

TCP客户端TcpClient

esp32tcpclient最大传输的数据长度