有点像:
+-------------------------------------------------------+
| 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 标头中的标志和字段。发送一个至少需要一个标头的带宽,再加上较低层附加的任何内容。但是数据段已经包含了所有这些......所以如果你正在发送数据,你可以同时免费发送一个 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 之上的应用层协议将有一些特定于协议的方式来确认发送和接收的数据。