2011-10-16 258 views
1

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

伪去:

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

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

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

您的代码

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

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

+0

我如何在连接上读取?是conn.Read一个io.Reader? – Nick

+1

是的,net.Conn实现了io.Reader,因为net.Conn有“Read(b [] byte)(n int,err os.Error)”方法。 – 2011-10-19 07:23:42

3

我在Go中没有直接的TCP使用经验,但对我来说,似乎你成了TCP提供的一种非常典型的误解的受害者。

事情是,与UDP和SCTP相比,TCP没有消息边界的概念,因为它是面向流的。这意味着,TCP传输不透明的字节流,并且很少控制关于接收端的“分块”流。

我怀疑你发现“发送100k +消息”是发送方的运行时间/网络库,通常是通过将你的“消息”消费到其内部缓冲区中,然后以任何块的形式进行流式处理来“欺骗”你的操作系统的TCP堆栈允许它(在无处不在的硬件/软件上通常大约8k)。接收器获取该流的片段大小完全未定义;唯一定义的是流中的字节的排序,它被保留。

因此,它可能会变成你不得不考虑你的方法来接收数据。确切方法取决于该数据的性质被流:

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

欲了解更多信息,看看thisthis

+0

我期望得到类似的东西,感谢有用的信息! – Nick