TCP 是否为每个发送的数据包打开一个新连接?

网络工程 通讯协议 网络 协议理论 传输协议 第4层
2021-07-05 15:33:44

这可能是一个愚蠢的问题,但我和几个小伙伴一直在讨论 TCP 的潜在局限性。我们有一个应用程序将侦听客户端(想想网关)并通过单个连接的 kafka 发布者将所有连接的客户端数据路由到一个主题。

我的一个朋友说 TCP 将成为这个网关的一个问题,因为它会为它发送的每条消息建立一个新连接(不是 kafka,而是底层传输协议本身的问题),每次都需要一个新端口。以我们发送这些客户端消息的速度(千兆字节),kafka 将用完要读取的端口??

我已经做了几年的开发,之前从未听说过这个,并且想对 TCP 的工作方式有一个较低层次的理解(我认为我已经理解了)。我的理解是,当您建立 TCP 连接时,该连接将保持打开状态,直到它被应用程序超时或被服务器或客户端强行关闭。通过此连接发送的数据是一个流,无论 3 V(音量、速度、种类)如何,都不会打开/关闭新连接。

就端口而言,一个端口用于广播,内部文件描述符端口是应用程序管理的用于读取/写入单个客户端的端口。我从来没有理解 TCP 为它写入的每个数据包建立新的连接。

如果这个问题不直接或太模糊,我提前道歉。我真的很困惑,希望有人可以为我的同事所说的话提供更多背景信息?

4个回答

我的一个朋友说 TCP 将成为这个网关的一个问题,因为它会为它发送的每条消息建立一个新连接(不是 kafka,而是底层传输协议本身的问题),每次都需要一个新端口。以我们发送这些客户端消息的速度(千兆字节),kafka 将用完要读取的端口??

你的朋友很困惑。TCP 是一种面向流的协议。它没有消息的概念。当然,它确实在 IP 层使用数据包,但对于应用程序来说,这是一个实现细节。TCP 会在有意义的地方插入数据包边界,而不必每个write()一次send()类似地,如果您在对read()或 的调用之间收到多个数据包,它会将连续的数据包组合在一起recv()

不用说,如果每次发送都建立一个新连接,这种面向流的设计将完全行不通。因此,建立新连接的唯一方法是手动关闭并重新打开连接。

(实际上,大多数建立在 TCP 之上的协议都有类似于消息的东西,例如 HTTP 请求和响应。但 TCP 不知道也不关心这些东西的结构。)

您的朋友可能正在考虑 UDP,它确实有消息,但也是无连接的。大多数套接字实现允许您将 UDP 套接字“连接”到远程主机,但这只是一种避免必须重复指定 IP 地址和端口的便捷方法。它实际上在网络级别没有做任何事情。不过,您可以手动跟踪您在 UDP 下正在与哪些对等方通话。但是如果你这样做,那么决定什么算作“连接”是你的问题,而不是操作系统的问题。如果您想在每条消息上重新建立“连接”,您可以这样做。然而,这可能不是一个好主意。

我的理解是,当您建立 TCP 连接时,该连接将保持打开状态,直到它被应用程序超时或被服务器或客户端强行关闭。

从 TCP 的角度来看,没有客户端或服务器(客户端/服务器是一个在这里跑题的应用程序概念)。TCP 在对等体之间建立连接,并且两个对等体都可以在该连接上发送和接收,直到任一对等体关闭它,或者它因不活动而超时。

通过此连接发送的数据是一个流,无论 3 V(音量、速度、种类)如何,都不会打开/关闭新连接。

这种情况可能令人困惑的是,某些应用程序(例如浏览器)将打开多个连接以同时加载诸如网页元素之类的内容。

TCP 不会为它发送的每个段打开一个新连接,但一个应用程序可能会打开多个 TCP 连接。此外,当 TCP 连接关闭时,连接中使用的 TCP 端口将被释放,并可再次使用。该答案提供了一些信息,并为您指明了 TCP 的 RFC。

不,TCP不需要为每个发送的数据包打开一个新连接。

您可以通过HTTP 持久连接的方式发送多个数据包,其中:

...发送和接收多个 HTTP 请求/响应 [使用] 的单个 TCP 连接,而不是为每个单个请求/响应对打开一个新连接。

附一张图,说明多连接(建立很多连接,每个连接发送一个对象)和长连接(建立一个连接,发送多个对象)的区别:

多连接与持久连接

来源:https : //www.vcloudnine.de/how-to-dramatically-improve-website-load-times/

正如其他人指出的那样,TCP 绝对允许连接在任何时间内保持打开状态,在此期间向任一方向交换任意数量的“消息”。也就是说,最终取决于应用程序(客户端和服务器)来确定是否使用了该功能。

为了重用现有的 TCP 连接(套接字),客户端应用程序必须保持该套接字打开,并在需要写入更多数据时使用它。如果客户端不这样做,而是丢弃旧的套接字并在每次需要时打开一个新的套接字,那么它确实会强制建立一个新的连接,如果这样做的频率足以耗尽,这可能会导致客户端或服务器上的资源问题TCP 堆栈的连接池。

同样,服务器必须足够聪明,以保持套接字在其一侧打开并等待更多数据。像客户端一样,它可以选择关闭套接字,此时希望发送更多数据的容错客户端别无选择,只能打开一个新的套接字,从而导致同样的问题。

最后,正如其他人所提到的,TCP 是面向流的。没有任何框架。仅仅因为一个对等方以特定方式写入数据(例如 1 1024 字节写调用,然后是 2 256 字节写调用),这并不能保证另一个对等方将以相同大小的块读取它(例如,它可能获得所有 1536 字节在一次阅读调用中)。因此,如果您通过原始 TCP 套接字发送多个“消息”,则必须提供自己的帧协议来描述不同的消息。虽然确实有一些简单的方法可以做到这一点,但通常是不明智的,因为有许多建立在 TCP 之上的协议来解决这个问题。如需进一步讨论,请参阅:https : //blog.stephencleary.com/2009/04/message-framing.html