如何在没有事先指定字节切片的长度的情况下阅读,使用golang中的net.TCPConn?

时间:2014-07-03 16:04:10

标签: tcp go

我试图从一个带有redis客户端的tcp连接中读取一些消息(一个运行redis-cli的终端)。但是,网络包的Read命令要求我将切片作为参数给出。每当我给出一个没有长度的切片时,连接崩溃并且go程序停止。我不确定我的字节消息需要在手的长度。因此,除非我指定一些非常大的切片,否则此连接将始终关闭,尽管这看起来很浪费。我想知道,是否有可能保持连接而不必事先了解消息的长度?我希望能解决我的具体问题,但我觉得这个问题比较笼统。为什么我需要事先知道长度?图书馆不能给我一个正确尺寸的片段吗?

或者人们建议的其他解决方案是什么?

2 个答案:

答案 0 :(得分:4)

不知道消息大小正是必须指定读取大小的原因(这适用于任何网络库,而不仅仅是Go)。 TCP是一种流协议。就TCP协议而言,消息将继续,直到连接关闭。

如果您知道您要在EOF之前阅读,请使用ioutil.ReadAll

致电Read并不能保证能为您提供所期待的一切。它可能会返回较少,可能会返回更多,具体取决于您收到的数据量。执行IO的库通常通过"缓冲区读取和写入&#34 ;;您将拥有"读取缓冲区",这是预先分配的字节片段(通常高达32k),并且每次要从网络读取时都重复使用该片段。这就是IO函数返回字节数的原因,因此您可以知道上一次操作填充了多少缓冲区。如果缓冲区已填满,或者您仍然需要更多数据,则只需再次致电Read

答案 1 :(得分:0)

有点晚了但是...

  1. 其中一个问题是如何确定消息大小。 JimB 给出的答案是 TCP 是一个流媒体协议,所以没有真正的结束。
  2. 我认为这个答案是不正确的。 TCP 将比特流分成连续的数据包。每个数据包都有一个 IP 标头和一个 TCP 标头 参见 Wikipediahere。每个数据包的 IP 标头都包含一个表示该数据包长度的字段。您必须进行一些数学运算才能减去 TCP 标头长度以得出实际数据长度。 此外,可以在 TCP 标头中指定消息的最大长度。
  3. 因此,您可以为读取操作提供足够长度的缓冲区。但是,您必须先读取数据包头信息。如果最大消息大小超过您愿意接受的长度,您可能不应该接受 TCP 连接。
  4. 通常,发送方会使用 fin 数据包(参见 1)而不是 EOF 字符来终止连接。
  5. 读取操作中的 EOF 很可能表明数据包未在指定时间内完全传输。