如果您通过一次调用中的套接字向send()发送数据,是否会在一次调用中接收到receive()?

时间:2010-09-30 18:17:03

标签: sockets

我已经看到了套接字的几种用法,程序员通过TCP / IP套接字发送命令或一些信息,并期望在接收端的一次调用中接收它。

例如,传输

mySocket.Send("SomeSpecificCommand")

他们假设接收方将在一次通话中接收所有数据。例如:

Dim data(255) As Byte   
Dim nReceived As Long = s.Receive(data, 0, data.Count, SocketFlags.None)
Dim str As String = Encoding.ASCII.GetString(data, 0, n)
If str = "SomeSpecificCommand" Then
    DoStuff()
    ...

上面的示例不使用任何终结符,因此程序员依赖于不允许套接字实现的事实,例如,在第一次调用Receive()和“cCommand”时返回“SomeSpecif”在稍后调用Receive()。 (注意 - 在示例中,缓冲区的大小应大于预期的字符串)。

我从来没有考虑过这么多想法,只是假设这种类型的编码是不安全的并且总是使用分隔符。我是在浪费时间(和处理器周期)吗?

5 个答案:

答案 0 :(得分:7)

无法保证全部同时到达。代码(应用程序的协议)需要处理来自一个发送的数据可能以多个部分到达的可能性,或者来自多个发送的数据可能到达一个接收的可能性。

答案 1 :(得分:1)

在对send()的一次短暂调用中发送的数据的短片段通常在一次调用recv()时到达,这就是为什么这样的代码大部分时间都会工作的原因。然而,它并不能保证,因此依赖它是不好的做法。

TCP缓冲数据,并可在其认为合适时将其拆分。 TCP尝试发送尽可能少的数据包以节省带宽,因此它不会毫无理由地分割数据。但是,如果它正在排队一些数据并且一次调用send()的数据碰巧跨越数据包边界,那么这些数据将被拆分。

或者,TCP可以尝试在一个数据包中发送它,但随后路由器的任何地方的路由器都会回来并说“这个数据包太大了!”。然后,TCP会将其拆分为更小的数据包。

答案 2 :(得分:1)

通过网络发送数据时,您应该期望数据在多个数据包中分段,并构建代码和数据以处理此问题。在您发送少量字节的示例情况下,一切都会正常工作..直到您开始发送更大的数据包。

如果您希望一次收到一条消息,那么您可以在第一个字节到达后的一段时间内循环读取字节。这很简单但效率低下。

可以按照建议使用分隔符,但是您必须防止在常规数据中意外包括分隔符。如果您只发送文本,则可以使用null或某些不可打印的字符。如果您要发送二进制数据,那么这将变得更加困难,因为数据中的任何分隔符都需要由发送方转义并由接收方解除转发。

分隔符的替代方法是在包含消息长度的数据前面添加一个字段。这比使用分隔符更好,因为它消除了转义数据的需要,而不仅仅是循环直到定时器到期,因为它会更具响应性。

答案 3 :(得分:0)

不,假设服务器(假设您的客户端)只向您发送一个套接字响应并不是一个好主意。服务器可以通过返回多个结果的过程列表运行。我会继续从套接字读取,直到没有任何东西可以拿起,然后等待几毫秒再次测试。如果没有显示任何内容,服务器完成发送响应的可能性很大。

答案 4 :(得分:0)

有几种类型的套接字。 TCP使用SOCK_STREAM,它不保留消息边界。 SOCK_SEQPACKET套接字确实保留了消息边界。

编辑:SCTP支持SOCK_STREAM和SOCK_SEQPACKET。