【问题标题】:How to read unknown data length in a TCP Client如何在 TCP 客户端中读取未知数据长度
【发布时间】:2014-09-07 17:13:52
【问题描述】:

我是 C# 的相对论新手。在我的 TCP 客户端中,有以下函数将数据发送到服务器并返回响应:

private static TcpClient tcpint = new TcpClient(); //Already initiated and set up
private static NetworkStream stm;                  //Already initiated and set up

private static String send(String data)
{
    //Send data to the server
    ASCIIEncoding asen = new ASCIIEncoding();
    byte[] ba = asen.GetBytes(data);
    stm.Write(ba, 0, ba.Length);

    //Read data from the server
    byte[] bb = new byte[100];
    int k = stm.Read(bb, 0, 100);

    //Construct the response from byte array to string
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < k; i++)
    {
        sb.Append(bb[i].ToString());
    }

    //Return server response
    return sb.ToString();
}

正如您在此处看到的,当我从服务器读取响应时,我将其读入一个长度为 100 字节的固定 byte[] 数组。

byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);

如果服务器的响应超过 100 字节,我该怎么办?在我不知道服务器数据的最大长度的情况下如何读取数据?

【问题讨论】:

  • 可以先发送数据长度再发送数据,或者使用数据中不存在的分隔符
  • @L.B 哦,好吧,这有点道理。所以我会有两个读取操作。第一个将获得数据长度。第二个将根据第一次读取操作中给出的长度获取实际数据。对吗?
  • 但是,如果你的字符串不包含换行符,使用var reader = new StreamReader(tcpint.GetStream()); 会更容易(另外还有StreamWriter)。这样,你只需要reader.ReadLine()writer.WriteLine()

标签: c# tcp bytearray tcpclient


【解决方案1】:

通常,如果某物没有特定的内在大小,tcp 协议会显式发送它们正在发送的对象的长度。一种可能的说明方法:

size_t data_len = strlen(some_data_blob);
char lenstr[32];
sprintf(lenstr, "%zd\n", data_len);
send(socket, lenstr, strlen(lenstr));
send(socket, some_data_blob, data_len);

然后当接收器读取长度字符串时,它确切地知道糊状数据应该如何遵循(良好的编程习惯是信任但验证——如果还有更多或真正发送的数据更少——比如说由一个'邪恶的演员'——你需要准备好处理它)。

【讨论】:

  • 太棒了!很有道理!
【解决方案2】:

不是关于 C#,而是关于编写 TCP 应用程序的一般答案:

TCP 是基于 Steam 的协议。它不维护消息边界。因此,使用 TCP 的应用程序应该注意在服务器和客户端之间选择正确的数据交换方法。如果在一个连接上发送和接收多条消息,则它变得更加重要。

一种广泛使用的方法是在数据消息前面加上长度字节。

例如:

[2 byte -length field][Actual Data].

此类数据的接收者(无论是服务器还是客户端需要解码长度字段,等待直到接收到尽可能多的字节的事件或在超时时发出警报并放弃。

另一个可以使用的协议是让应用程序维护消息边界。

例如: `[START-of-MSG][Actual Data][END-of-MSG]

接收者必须解析起始字节和结束字节的数据(由应用程序协议预定义),并将其间的任何内容视为感兴趣的数据。

【讨论】:

    【解决方案3】:

    你好,我用列表解决了,我不知道完整包的大小,但我可以部分阅读

    List<byte> bigbuffer = new List<byte>();
    
    byte[] tempbuffer = new byte[254]; 
    //can be in another size like 1024 etc.. 
    //depend of the data as you sending from de client
    //i recommend small size for the correct read of the package
    
    NetworkStream stream = client.GetStream();
    
    while (stream.Read(tempbuffer, 0, tempbuffer.Length) > 0) {
    
        bigbuffer.AddRange(tempbuffer);
    } 
    
    // now you can convert to a native byte array
    byte[] completedbuffer = new byte[bigbuffer.Count];
    
    bigbuffer.CopyTo(completedbuffer);
    
    //Do something with the data
    string decodedmsg = Encoding.ASCII.GetString(completedbuffer);
    

    我用图像做这个,看起来不错,我认为如果 porpouse 被读取一个大小未知的完整源,你不知道数据的大小

    【讨论】:

    • o可以接收tcpclient对象的ReceiveBufferSize属性
    【解决方案4】:

    我四处寻找这个问题的答案,并注意到可用属性已添加到 TcpClient。它返回可供读取的字节数。

    我假设它是在大多数回复之后添加的,所以我想分享给其他可能偶然发现这个问题的人。

    https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.available?view=netframework-4.8

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 2021-09-05
      • 2022-06-29
      • 2016-12-06
      • 1970-01-01
      • 2014-12-01
      相关资源
      最近更新 更多