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

发布于 2024-09-16 18:16:58 字数 381 浏览 4 评论 0原文

我有一个 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 是否有任何好处?

I have a TCP server that listens for an incoming client, then sends it one packet of data every second. I was wondering, does the SYN/ACK packet only get sent on initial connection, so it looks like this:

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

Or does it get sent with every packet, like this?

<client connect>
SYN
ACK
DATA

SYN
ACK
DATA

SYN
ACK
DATA
<client disconnect>

Also, if it's the first case, are there any benefits of UDP over TCP if you just keep the connection open over a long period of time?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北斗星光 2024-09-23 18:16:58

有点像:

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

It's kinda like:

+-------------------------------------------------------+
|     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 starts a connection; you'll usually only see it when the connection's being established. But all data being sent via TCP requires an ACK. Every byte sent must be accounted for, or it will be retransmitted (or the connection reset (closed), in severe cases).

Actual connections aren't usually exactly like the diagram above, though, for two reasons:

  • ACKs can build up, so one ACK can acknowledge everything received up to that point. That means you can acknowledge two or more sends with one ACK.
  • An ACK is simply a flag and field in a TCP header. Sending one requires at least a header's worth of bandwidth, plus whatever the lower layers tack on. But data segments already include all that...so if you're sending data, you can send an ACK at the same time for free.

Most TCP/IP stacks try to reduce the number of naked ACKs without unduly risking retransmission or a connection reset. So a conversation like this one is quite possible:

\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
|                 |                |                    |
|                 | <--- 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 ----> |                    |
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/

As for UDP, there's no built-in concept of SYN and ACK -- UDP is by nature "unreliable", and not connection-oriented, so the concepts don't apply as much. Your acknowledgement will usually just be the server's response. But some application-layer protocols built on top of UDP will have some protocol-specific way of acknowledging data sent and received.

携余温的黄昏 2024-09-23 18:16:58

SYN仅在开始处。

ACK 位于任一方向的后续段上。 ACK 还将定义窗口大小。例如,如果窗口大小为 100,则发送方可以在期望收到 ACK 之前发送 100 个分段。例如,如果发送方发送 100 个段,但第 50 个段丢失,则接收方将得到 1-49 和 1-49。 51 -100。然后,接收方将确认 50(它期望的下一个数据段)并将窗口大小设置为 1。发送方将重新发送序列号为 50 的 1 个数据段。然后接收方将确认 101,并将窗口大小设置回更高的数字。

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

因此,您描述的两种情况都不完全正确。第一个实际上更接近现实,但是 SYN 之后的所有数据包都必须包含 ACK,以及一个确认号字段,用于标识预期的下一个数据包的编号。

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

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

此外,如果是第一种情况,如果您只是长时间保持连接打开,UDP 相对于 TCP 是否有任何好处?

使用 UDP,您不能只是长时间保持连接打开。没有任何联系。

SYN/ACK/FIN 标志序列就是建立连接的依据。

使用 UDP 时,没有 SYN 或 ACK,因此通信是单向的,无法保证交付且不保留顺序。但它的开销较小,因此当速度比可靠性更重要时(例如在流媒体中),它非常有用。

这还有点简化,但这是我目前能做的最好的事情。

关于 TCP 的维基百科条目以及 RFC 中对此有更多内容。

SYN is only at the beginning.

ACK is on subsequent segments in either direction. The ACK will also define a window size. If the window size is 100 for example, the sender can send 100 segments before it expects to receive an ACK. E.g If sender sends 100 segments but segment number 50 gets lost, then receiver will get 1-49 & 51 -100. Receiver will then ACK for 50 (next segment it expects) and set window size to 1. Sender will resend 1 segment with sequence number 50. Receiver will then ACK for 101 and set the window size back up to a higher number.

Both are actually fields in the TCP header and can be sent with data, though the SYN and the first ACK typically are data-less.

So neither of the scenarios you describe is quite correct. The first is actually closer to reality, but all the data packets after the SYN do have to include an ACK, and also an acknowledgement number field which identifies the number of the next packet expected.

The end of a session also involves handshakes with FIN flagged packets and ACKs relating to them.

The exchanged sequence numbers are used to identify lost packets and enable a retry mechanism, and also to reassemble the entire stream of packets in the correct order.

Also, if it's the first case, are there any benefits of UDP over TCP if you just keep the connection open over a long period of time?

With UDP you can't just keep the connection open over a long period of time. There is no connection.

This sequence of SYN/ACK/FIN flags is what makes a connection.

With UDP, there are no SYNs or ACKs, so communication is one-way, delivery is not guaranteed and order is not preserved. But it has less overhead, so it's useful when speed is more important than reliability, as for example in streaming media.

This is a bit simplified yet, but it's the best I can do at the moment.

There's much more on this in the wikipedia entry on TCP and of course in the RFCs.

日暮斜阳 2024-09-23 18:16:58

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

Dordal 对这个问题有一个非常好的解释。单击此处的链接。

Picture this:
The original TCP standard RFC 793 allowed data to be sent with the first SYN packet though. However, that's not the case today. What you get is a separate SYN packet during initiation of the Three-Way-Handshake from the requestor of the connection. Suppose A requests to connect with B, thus A sends a packet with a SYN bit set. B responds with an ACK to acknowledge receipt and sends A the ACK + SYN packets. Data can then be transmitted henceforth.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文