Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 如何通过Go中的套接字检索文件数据?_Sockets_Go - Fatal编程技术网

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

Sockets 如何通过Go中的套接字检索文件数据?,sockets,go,Sockets,Go,我有两个小程序,它们通过一个套接字很好地通信,接收端在这个套接字中。当我的消息足够小,可以放入1024字节的缓冲区,并且可以从连接中一次读取接收时,一切都很顺利,但现在我想从100k+或更高的图像传输数据。我假设正确的解决方案是在任何图像都可以放入之前不增加缓冲区 伪围棋: var buf = make([]byte,1024) conn, err := net.Dial("tcp", ":1234") for { r, err := conn.Read(buf[0:]) 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中使用,那么您将获得额外的积分。

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

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

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

因此,您可能不得不重新考虑接收数据的方法。确切的方法因所传输数据的性质而异:

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

欲了解更多信息,请查看和。

我在Go中没有直接使用TCP的经验,但在我看来,您似乎是对Gurantees TCP所提供内容的典型误解的受害者

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

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

因此,您可能不得不重新考虑接收数据的方法。确切的方法因所传输数据的性质而异:

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

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

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

你的代码

for {
    r, err := conn.Read(buf[0:])
    go readHandler(string(buf[0:r]),conn)
}
似乎是在暗示您正在启动的goroutine正在从
conn
读取这似乎不是一个好主意,因为您最终将从连接进行多个并发读取(而无法控制读取的顺序):for循环中的一个,
readHandler
中的另一个可以用来读取特定长度的
[]字节。这假设您事先知道需要读取多少字节

对于
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[]字节)(n int,err os.Error)”方法。如何在conn上读取完整信息?conn.Read是io.Reader吗?是的,net.conn实现io.Reader,因为net.conn有“Read(b[]字节)(n int,err os.Error)”方法。