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

时间:2010-08-30 21:47:12

标签: 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 over TCP是否有任何好处?

3 个答案:

答案 0 :(得分:74)

有点像:

+-------------------------------------------------------+
|     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之上构建的一些应用层协议将具有一些特定于协议的方式来确认发送和接收的数据。

答案 1 :(得分:10)

SYN仅在开始时。

ACK在任一方向的后续段上。 [edit] ACK还将定义窗口大小。例如,如果窗口大小为100,则发送方可以在期望接收ACK之前发送100个段。例如,如果发送者发送100个段但段号50丢失,则接收者将获得1-49&amp; 51 -100。接收器然后将确认50(它预期的下一个段)并将窗口大小设置为1.发送器将重新发送序列号为50的1个段。接收器然后将确认101并将窗口大小设置回更高的数字[编辑] < / p>

两者实际上都是TCP头中的字段,可以与数据一起发送,尽管SYN和第一个ACK通常都是无数据的。

因此,您描述的情景都不正确。第一个实际上更接近现实,但SYN之后的所有数据包都必须包括ACK,还有一个确认号字段,用于标识预期的下一个数据包的数量。

会话结束还涉及握手FIN标记的数据包和与之相关的ACK。

交换的序列号用于识别丢失的数据包并启用重试机制,并以正确的顺序重新组装整个数据包流。

  

另外,如果是第一种情况,如果你只是在很长一段时间内保持连接打开,那么UDP over TCP是否有任何好处?

使用UDP,您不能长时间保持连接打开状态。没有联系。

此序列的SYN / ACK / FIN标志是连接的原因。

使用UDP时,没有SYN或ACK,因此通信是单向的,不保证传送,并且不保留顺序。但它具有较少的开销,因此当速度比可靠性更重要时,例如在流媒体中,它是有用的。

这有点简化了,但这是我现在能做的最好的事情。

wikipedia entry on TCP中有更多内容,当然还有RFC。

答案 2 :(得分:0)

想象一下: 最初的TCP标准RFC 793允许使用第一个SYN数据包发送数据。但是,今天情况并非如此。在从连接请求者发起三方握手期间,您得到的是一个单独的SYN数据包。假设A请求与B连接,因此A发送一个SYN位设置的数据包。 B以ACK响应以确认接收并发送A ACK + SYN分组。然后可以传输数据。

Dordal has a very good explanation on this matter. Click this link here.