套接字协议基础知识

11

最近,我在阅读 Socket编程指南 时,注意到了以下部分:

但是,如果您计划重用套接字进行更多的传输,请注意套接字上没有“EOT”(传输结束)。 我再说一遍:如果套接字 send 或 recv 处理 0 字节后返回,则连接已断开。 如果连接未被断开,则可能会永远等待 recv,因为套接字不会告诉您没有更多内容可读取(暂时)。 如果您仔细考虑一下,就会意识到 socket 的一个基本真理:消息必须是 固定长度(不好看),或者 有定界符(耸肩),或者 指示其长度(更好),或者 通过关闭连接来结束。 这个选择完全取决于您,(但某些方法比其他方法更正确)。

这部分突出了 socket “协议”可能编写传递消息的4种可能性。我的问题是,对于实际应用程序来说,哪种是首选方法?

通常最好在每条消息中包含消息大小(可能在标头中),正如文章所断言的那样吗?是否有任何情况下另一种方法更可取?


上面的链接已经失效。 - cdosborn
这是关于Python套接字编程的内容,新链接为https://docs.python.org/2/howto/sockets.html。 - HUA Di
5个回答

5

常见的协议要么在头部指定长度,要么是定界符(例如HTTP)。

请记住,这也取决于您使用TCP还是UDP套接字。由于TCP套接字是可靠的,因此您可以确信您放入其中的所有内容都会被接收。对于UDP,情况则不同且更为复杂。


+1,使用UDP固定长度是正确的方法。如果您无法将所有内容放入一个数据包中,则可能无法将其重新组合。 - Carl Norum
1
为什么这很重要呢?如果UDP数据包在传输过程中被破坏,IP层将不会将其转发到您的应用程序,因此缺少其中一部分就等于全部丢失,对吧?我已经很久没有编写网络应用程序了,恐怕有些生疏。 - Carl Norum
2
“由于TCP套接字是可靠的,你可以确信你得到了所有你塞进去的东西”这种说法是一个可怕的误解。你可以确信你按照正确的顺序接收到了所有数据流,并且数据流以你实际想要的开始为起点,但是如果不使用应用层协议结构来确定结束位置,你永远无法确定它是否在预期的位置结束。 - user61465
@Mart:抱歉,我不确定你的意思。如果你将“abcde”写入TCP套接字中,最终会在接收端得到它。 - Eli Bendersky
1
不,没有这样的保证。你可能会丢失从TCP连接中的数据流的结尾(其中“结尾”可能很容易从发送到套接字的第一个字节开始)。尝试在高RTT和包丢失率的不稳定网络中使用TCP,你会发现关于TCP的不可靠性有些令人惊讶的事情。 - user61465

2
这确实是我们在TCP中的选择。例如,HTTP使用第二、第三和第四个选项的混合(双换行符结束请求/响应头,其中可能包含Content-Length标头或指示分块编码,也可能说Connection: close并且不提供内容长度但期望您依靠读取EOF)。
我更喜欢第三个选项,即自描述消息,尽管适当时固定长度很容易。

2
如果你正在设计自己的协议,那么先看看其他人的工作;可能已经有类似的东西存在,你可以直接使用或重新调整。例如:ISO-8583 用于金融交易,HTTPPOP3 都以不同的方式完成任务,但都已被证明有效...实际上,无论如何都值得研究这些东西,因为你会学到很多关于现实世界协议的组成方式。
如果你需要编写自己的协议,那么在可能的情况下请优先选择长度前缀消息。对于接收者来说,它们易于解析且高效,但是如果在开始发送数据之前确定数据的长度成本较高,则可能更难生成。

2
决定应该取决于您要发送的数据(是什么,如何收集)。如果数据长度固定,则固定长度数据包可能是最好的选择。如果数据可以轻松地(无需转义)分成分隔实体,则分隔可能是一个好的选择。如果在开始发送数据片段时就知道数据大小,则前缀长度可能会更好。如果发送的数据始终是单个字符,甚至是单个比特(例如,“开”/“关”),则与固定大小的单个字符消息不同的任何内容都将过多。
还要考虑协议可能如何发展。以EOL为分隔符的字符串很好,只要它们本身不包含EOL字符即可。固定长度可能很好,直到数据可以用一些可选部分扩展为止,等等。

类似于“以行尾符为定界符的字符串很好,只要它们本身不包含行尾字符”,使用零字节作为ASCII编码消息的定界符是一个坏主意吗? - Anakhand

1

我不知道是否有首选选项。在我们的实际情况(客户端-服务器应用程序)中,我们使用将总消息长度作为第一批数据之一发送的选项。它简单易行,并适用于我们的TCP和UDP实现。在读取两种情况下的数据时,它使逻辑相对“简单”。与TCP相比,代码量相当小。UDP版本有点(轻描淡写)更复杂,但仍依赖于传递给初始数据包的大小,以知道何时发送了所有数据。


一个很好的选择。当程序员没有使用无效的消息进行测试时,实现可能容易受到缓冲区溢出的攻击。 - Zan Lynx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接