【问题标题】:How do I retrieve file data over a socket in Go?如何通过 Go 中的套接字检索文件数据?
【发布时间】:2011-12-08 17:46:18
【问题描述】:

我有两个小程序通过接收端在 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,则可获得奖励积分。

【问题讨论】:

    标签: sockets go


    【解决方案1】:

    我对 Go 中的 TCP 没有直接经验,但在我看来,您似乎是对 TCP 提供的保证的典型误解的受害者。

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

    我怀疑您所观察到的“发送 100k+ 条消息”是发送方的运行时/网络库,通常通过将您的“消息”消耗到其内部缓冲区中然后将其流式传输到操作系统的 TCP 堆栈中的任何块中来“欺骗”您允许它(在无处不在的硬件/软件上通常约为 8k)。接收者获得该流的片段大小是完全未定义的;唯一定义的是流中 bytes 的顺序,这是保留的。

    因此,您可能必须重新考虑接收数据的方法。具体方法因流式传输数据的性质而异:

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

    如需了解更多信息,请查看thisthis

    【讨论】:

      【解决方案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

      【讨论】:

      • 如何在 conn 上阅读全文? conn.Read 是 io.Reader 吗?
      • 是的,net.Conn 实现了 io.Reader,因为 net.Conn 有 "Read(b []byte) (n int, err os.Error)" 方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      相关资源
      最近更新 更多