我试图理解带有
PSH
标志的 TCP 段和带有 URG
标志的 TCP 段之间的区别。
我阅读了 RFC 但仍然无法获取它,其中一个在将数据发送到进程之前是否缓冲数据,而另一个则没有?
它们是两种截然不同的机制。
当您发送数据时,您的
TCP
会对其进行缓冲。因此,如果您发送一个字符,它不会立即发送,而是等待查看是否有更多字符。但也许您希望它直接在线:这就是 PUSH 功能的用武之地。如果您 PUSH 数据,您的 TCP 将立即创建一个段(或几个段)并push它们。
但故事并没有就此结束。当对等 TCP 接收到数据时,它会自然地缓冲它们不会干扰每个字节的应用程序。这就是
PSH
标志发挥作用的地方。如果接收 TCP 看到 PSH 标志,它将立即将数据push 到应用程序。
没有 API 可以设置
PSH
标志。通常它是由内核清空缓冲区时设置的。来自 TCP/IP 图解:
该标志通常用于指示发送数据包一侧的缓冲区已被使用 与发送数据包的同时清空。换句话说,当设置了 PSH 位字段的数据包离开发送方时,发送方没有更多数据可发送。
但请注意史蒂文斯也说:
推送(接收者应尽快将此数据传递给应用程序) 可能—未可靠实施或使用)
TCP 是一种面向流的协议。因此,如果您在一侧推送 64K 字节,最终您将在另一侧获得 64K 字节。因此,想象一下您推送了大量数据,然后收到一些消息,上面写着“嘿,您知道我刚刚发送的所有数据吗?是的,把它们扔掉”。问题的要点是,一旦您在连接上推送数据,您就必须等待接收方获取所有数据,然后才能获取新数据。
这就是
URG
标志发挥作用的地方。当您发送紧急数据时,TCP 会创建一个特殊的段,在其中设置 URG 标志以及紧急指针字段。这会导致接收 TCP 在单独的通道上将紧急数据转发到应用程序(例如,在 Unix 上,您的进程会收到 SIGURG
)。这允许应用程序处理数据带外。顺便说一句,重要的是要意识到紧急数据现在很少使用并且没有得到很好的实施。使用单独的渠道或完全不同的方法要容易得多。
¹:RFC 6093
不同意这种“带外”的使用,并指出:TCP紧急机制不是发送“带外”的机制 数据:所谓的“紧急数据”应“在线”交付给 TCP 用户。
但随后它又承认:
默认情况下,“紧急数据”的最后一个字节是“带外”传送的 到应用程序。也就是说,它不作为 正常数据流。
应用程序必须特意指定,例如
SO_OOBINLINE
获得符合标准的紧急语义。如果这一切听起来很复杂,只是不要使用紧急数据
。在已回答的基础上添加更多信息。
如果设置了
URG
位,则优先考虑数据,这意味着紧急数据将紧急发送,而不是等待“紧急”数据之前的整个字节流被传输,而不会等待用于传输前面的整个字节流。当
URG
位被设置时,紧急指针也被设置(在
TCP
标头选项字段中:16 位)。 URG
指针告诉已到达的段中有多少字节的数据是紧急的。 (例如,如果数据大小为 100 字节,并且只有前 50 字节是紧急的,则紧急指针的值为 50)。现在来到
PSH
位。
PSH
位的目的是告诉TCP不要等待缓冲区变满并立即发送数据。同样,当接收方收到设置了
PSH
标志的报文段时,应立即将数据发送到上层,而无需等待接收缓冲区变满。实际的例子是 telnet 应用程序,其中应用程序以很少的击键形式发送数据。如果 telnet 等待缓冲区变满后再将数据传输到接收方,那么 telnet 将无法使用。我不会过于严格地接受 RFC 中的所有内容,这些标志的实现似乎存在一些含糊之处。 URG 涉及在填充缓冲区之前发送数据包,而 PSH 控制在接收端将数据向上移动到堆栈。