networking - TCP 是在每个数据包上发送 SYN/ACK 还是仅在第一个连接上发送?

标签 networking tcp udp client-server packet

我有一个 TCP 服务器监听传入的客户端,然后每秒向它发送一个数据包。我想知道,SYN/ACK 数据包是否只在初始连接时发送,所以它看起来像这样:

<client connect>
SYN
ACK
DATA
DATA
DATA
<client disconnect>

还是像这样随每个数据包一起发送?

<client connect>
SYN
ACK
DATA

SYN
ACK
DATA

SYN
ACK
DATA
<client disconnect>

此外,如果是第一种情况,如果长时间保持连接打开,UDP 比 TCP 有什么好处吗?

最佳答案

有点像:

+-------------------------------------------------------+
|     client           network            server        |
+-----------------+                +--------------------|
|    (connect)    | ---- SYN ----> |                    |
|                 | <-- SYN,ACK -- |     (accepted)     |
|   (connected)   | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

when client sends...
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|     (send)      | ---- data ---> |                    |
|                 | <---- ACK ---- |  (data received)   |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

when server sends...
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|                 | <--- data ---- |       (send)       |
| (data received) | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

...and so on, til the connection is shut down or reset

SYN 开始一个连接;您通常只会在建立连接时看到它。但是所有通过 TCP 发送的数据都需要 ACK。必须考虑发送的每个字节,否则将重新传输(或在严重情况下重置(关闭)连接)。

不过,实际连接通常完全如上图所示,原因有二:

  • ACK 可以累积,因此一个 ACK​​ 可以确认到此为止收到的所有内容。这意味着您可以用一个 ACK​​ 确认两个或多个发送。
  • ACK 只是 TCP header 中的标志和字段。发送一个至少需要一个 header 的带宽,加上较低层的带宽。但是数据段已经包含了所有这些……所以如果您要发送数据,您可以免费同时发送一个 ACK​​。

大多数 TCP/IP 堆栈都试图减少裸 ACK 的数量,而不会过度冒重传或连接重置的风险。所以像这样的对话是很有可能的:

\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|                 | <--- data ---- |       (send)       |
| (data received) |                |                    |
|     (send)      | -- data,ACK -> |                    |
|                 |                |  (data received)   |
|                 | <- data,ACK -- |       (send)       |
| (data received) |                |                    |
|  (wait a bit)   | <--- data ---- |       (send)       |
| (data received) |                |                    |
|     (send)      | -- data,ACK -> |                    |
|                 |                |  (data received)   |
|     (send)      | ---- data ---> |   (wait a bit)     |
|                 |                |  (data received)   |
|                 | <- data,ACK -- |       (send)       |
| (data received) |                |                    |
|  (wait a bit)   |   (dead air)   |                    |
|                 | ---- ACK ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

至于 UDP,没有 SYN 和 ACK 的内置概念——UDP 本质上是“不可靠的”,而不是面向连接的,因此这些概念并不适用。您的确认通常只是服务器的响应。但是一些建立在 UDP 之上的应用层协议(protocol)将有一些协议(protocol)特定的方式来确认发送和接收的数据。

关于networking - TCP 是在每个数据包上发送 SYN/ACK 还是仅在第一个连接上发送?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3604485/

相关文章:

java - 为 C++ 服务器实现 Java TCP 客户端

Java Swing 更新

wcf - 使用 SSL 和证书对 wcf 的查询很少

c - 为什么特定的 UDP 消息总是被丢弃到低于特定的缓冲区大小?

networking - 什么是连接?

c - 使用 Winsock 接收数据

ios - 链接到伞形框架

networking - TCP/IP 校验和有多稳健

networking - SYN Cookie 在 Linux 中的实现

Java UDP 数据报包