如何通过Go中的套接字检索文件数据?

时间:2011-10-16 13:53:23

标签: sockets go

我有两个小程序通过套接字很好地通信,其中接收方在Go中。当我的消息足够小以适应1024字节缓冲区并且可以从连接中的单个读取接收但现在我想从100k +或更多的图像传输数据时,一切都工作得很好。我假设正确的解决方案是不增加缓冲区,直到任何图像都适合内部。

伪转到:

var buf = make([]byte,1024)
conn, err := net.Dial("tcp", ":1234")

for {
    r, err := conn.Read(buf[0:])
    go readHandler(string(buf[0:r]),conn)
}

如何改进套接字读取例程以接受几个字节的简单消息以及更大的数据?如果您可以将总图像数据转换为io.Reader以在image.Decode中使用,则可获得奖励。

2 个答案:

答案 0 :(得分:3)

我在Go中没有使用TCP的直接经验,但对我而言,您似乎成为了一个典型的误解TCP TCP提供的内容的受害者。

与UDP和SCTP形成鲜明对比的是,TCP没有消息边界的概念,因为它是面向流的。这意味着,TCP传输不透明的字节流,并且您几乎无法控制与接收方相关的流的“分块”。

我怀疑你所发现的“发送100k +消息”是发送方的运行时/网络库通常会“欺骗”你的内容缓冲区消耗你的“消息”然后在任何块的OS的TCP堆栈中流式传输它允许它(在无处不在的硬件/软件上通常约为8k)。接收器获取该流的大小完全未定义;唯一定义的是流中 bytes 的排序,这是保留的。

因此,您可能需要重新接受接收数据的方法。具体方法取决于流式传输数据的性质:

  • 最简单的方法(如果您可以控制应用程序级协议)是在固定格式的特殊长度字段中传递以下“消息有效负载”的长度。然后对整个消息进行定位是一个两步过程:1)接收那么多字节来获取长度字段,读取它,检查值是否合理,然后2)读取许多后续字节并完成它。
  • 如果您无法控制应用级协议,则解析消息会变得更加复杂,并且通常需要某种复杂的状态机。

有关详细信息,请查看thisthis

答案 1 :(得分:2)

您可以使用io.ReadFull来阅读特定长度的[]byte。这假设您事先知道需要读取多少字节。

对于image.Decode,应该可以将conn直接传递给image.Decode函数。这假设您在解码图像之前不会从连接执行任何读取。

您的代码

for {
    r, err := conn.Read(buf[0:])
    go readHandler(string(buf[0:r]),conn)
}

似乎暗示你正在开始的goroutine是从conn读取这似乎不是一个好主意,因为你最终会从连接中读取多个并发 (无法控制读取的顺序):for循环中的一个,readHandler中的另一个。