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 为什么我不能激发TCP将send()拆分为多个recv()呢_Sockets_Blocking_Recv - Fatal编程技术网

Sockets 为什么我不能激发TCP将send()拆分为多个recv()呢

Sockets 为什么我不能激发TCP将send()拆分为多个recv()呢,sockets,blocking,recv,Sockets,Blocking,Recv,我对套接字的长期理解是,不能依赖对recv()的调用来返回请求的数据量(无论是否阻塞套接字) 我试图通过在一次通话中发送大量(1mb)数据来向同事证明这一点(从我家,通过works VPN网络发送到他的家-涉及多个路由器wifi等) 套接字正在阻塞,因此我不希望send()返回1mb以外的任何内容,并一次性完成,但我确实希望recv()调用返回的内存小于1mb,即使套接字正在阻塞 此测试的背景是说服他,我们需要消息协议中的长度和有效负载,以便您知道消息的开始/结束位置,并且您不能依靠一个recv

我对套接字的长期理解是,不能依赖对recv()的调用来返回请求的数据量(无论是否阻塞套接字)

我试图通过在一次通话中发送大量(1mb)数据来向同事证明这一点(从我家,通过works VPN网络发送到他的家-涉及多个路由器wifi等)

套接字正在阻塞,因此我不希望send()返回1mb以外的任何内容,并一次性完成,但我确实希望recv()调用返回的内存小于1mb,即使套接字正在阻塞

此测试的背景是说服他,我们需要消息协议中的长度和有效负载,以便您知道消息的开始/结束位置,并且您不能依靠一个recv()调用返回一条消息。此外,为了向他展示一个简单的recv()是不够的,如果我们有这个协议,我们需要在循环中recv(),即使对于4字节的消息长度字段,如果recv()不返回请求的大小

我对TCP通信的理解是错误的吗?这些年我是不是做得太过分了?如果没有,我如何强制这些recv()以碎片形式出现

说服他我们需要消息协议中的长度和有效负载,以便您知道消息的开始/结束位置

你肯定需要这样做,如果你需要说服你的同事这样做,让他们解释为什么不这样做。一个send()不对应于一个recv(),句点。当然,这在某些条件下可能发生。现在互联网速度很快,默认情况下Nagle是启用的


尝试相反的方法,发送1000条小消息,让它们从一个或多个recv()调用的结果中分离出单独的消息;如果没有适当的信息框架,他们就不可能成功。

你的同事错得很危险。你根本无法从无法思考或观察某件事情可能出错的方式中得到保证。要么保证接收将对应于发送,要么没有

观察在这里没有帮助

  • 如果您没有观察到与发送不对应的接收,则可能是您观察到它的实现中的一个bug

  • 如果您观察到与发送相对应的接收,可能是因为您正在测试的实现有一些不寻常的地方,并且操作系统、编译器、标准库等的下一个版本可能不符合这些假设

  • 要么你的同事依赖于有保证的行为,要么不是。答案是他们不是


    90年代末的真实故事:我曾经不得不调试一些“总是工作得很好”的代码,因为它期望TCP连接的前12个字节保持在一起。当发现一次攻击涉及使用8个精心编制的恶意字节,并且在客户所在地使用的防御是一个过滤器,该过滤器在将所有TCP连接的前8个字节传递给应用程序之前拦截并检查这些字节时,该漏洞就断开了。因此,应用程序在第一次调用
    recv
    时总是读取前8个字节(来自筛选器),违反了(中断的、愚蠢的)假设,即在TCP连接开始时读取12个字节总是得到全部12个字节。

    我确实在一次发送中发送了两个有效负载,在两次发送中发送了两个半负载,从而破坏了它们的一方,他们拒绝接受,如果我没有恶意这么做,那么它就会起作用(即TCP会确保他们的1 recv()会收到一条消息)。此外,我觉得实际向他们展示分裂的发生将毫无疑问地证明,就他们而言,如果没有发生,它就不存在,我们最终在协议中得到了长度,我用我这边的,但他没有,他只是发出一个recv()并说如果我发送一条消息,他会收到一条消息,他没有读取长度,然后读取该长度的有效载荷。你的协议是否有能力给接收方一记耳光;tcp保证按顺序传递数据,而不是消息。Berkeley套接字记录为对
    recv()
    的调用,返回接收缓冲区中的内容。到目前为止,所有消息都在缓冲区中,这对您的同事来说是件好事,但这并不能保证。一个网络故障,一个丢失和重新传输的数据包,一个操作系统决定返回缓冲区中一半的消息,他们的代码将被破坏。当他们以他们认为有效的方式解释文档时,是的,文档提到了消息——但那是UDP,不是TCP。TCP不说消息,而是流式传输。因此,基本上,它可以在工厂中正常工作,然后我们部署到客户站点,他们的特定基础设施可能会显示问题。谢谢,我会用这个作为另一个战术。我很惊讶你在一次接收中获得了所有1MB。在从
    recv()
    调用返回之前,可能会缓冲数百个数据包。试试10MB,甚至100MB。这就是我的想法!,1mb,没有拆分,不太可能。我开始怀疑它是否是VPN软件,因此它与我们之间的网络类型无关,VPN S/W有效地允许在另一端重建无限大小的TCP数据包?也许我会在家里用两台笔记本电脑通过wifi?对,所以我做了一个每秒发送16k心跳的noddy应用程序,在家里完全通过wifi。走出房子,HB停止了,我没有收到一次部分recv(),它暂停了,但当我回到范围继续时,我没有提到,我们使用SSL进行连接,但我们对SSL和非SSL进行了大量测试。我上面的noddy 16k测试是在SSL(C#SslStream包装TCPClient.GetStream)上完成的。如果我的读卡器在链接时等待5秒后才发出读取,并且我确保我的发送者在这段时间内发送了两条不同的消息,那么接收方将获得两条读取!!!!!但是,如果我切换到非ssl(使用Client.GetStream或Client.Client),则读取器会将这两条消息都接收进来