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


15

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

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

我从事开发工作已经有几年了,以前从未听说过它,并且希望对TCP的工作原理有一个较低的了解(我认为我已经知道)。我的理解是,当您建立TCP连接时,该连接将保持打开状态,直到应用程序将其超时或服务器或客户端强行关闭该连接为止。通过此连接发送的数据是流,无论3 V(体积,速度,变化)如何,都不会打开/关闭新连接。

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

如果这个问题不是直接的,或者太含糊,我事先表示歉意。我真的感到莫名其妙,希望有人能为我的同事们提供更多的背景信息?


13
我认为您误解了朋友在说什么。TCP不会做这种事情,但是某个客户端可能会为其要传递的每条消息建立一个新的TCP连接
霍布斯

13
TCP不可能为每个数据包打开一个新的连接,因为它需要几个数据包才能打开一个新的连接。而且它无法为每条消息打开新的连接,因为TCP没有消息的概念。你的朋友很困惑。关于TCP的最重要的理解是最基本的概念,即TCP是字节流协议。
戴维·史瓦兹

1
您的伙伴的论点不一定是错误的-如果您不通过应用程序级保持活动重用端口,或者客户端太多,则系统可能会耗尽临时端口。有解决此问题的方法:SO_REUSEADDR用于更快地关闭套接字,增加临时端口的范围等。此外TCP_FASTOPEN,可以使用多个OS级别的切换来解决TCP的其他众所周知的限制。无论哪种方式,即使您没有要测试的工作量,也没有必要讨论TCP的限制。
user1643723 '18

Answers:


22

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

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

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

(实际上,大多数建立在TCP之上的协议都具有类似于消息的内容,例如HTTP请求和响应。但是TCP并不知道或不在乎此类结构。)

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


9

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

从TCP的角度来看,没有客户端或服务器(客户端/服务器是此处未提及的应用程序概念)。TCP在对等方之间建立连接,并且两个对等方都可以在该连接上进行发送和接收,直到任一对等方将其关闭或由于不活动而超时。

通过此连接发送的数据是流,无论3 V(体积,速度,变化)如何,都不会打开/关闭新连接。

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

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


2
尽管在TCP中,有一个伙伴发起了连接(通常称为“客户端”),而另一个则发起了连接(通常称为“服务器”)。当然,建立连接后,这种区别不再重要。
圣保罗Ebermann

2
@PaŭloEbermann,TCP RFC中没有有关客户端或服务器的任何内容。客户端/服务器概念是一个应用程序概念。此处讨论的是OSI 4层或以下的协议,并且这些协议中没有客户端或服务器。实际上,您可能假定为客户端(打开TCP连接的客户端)实际上可能是应用程序服务器。我们的服务器确实启动与客户端的TCP连接,以执行安全检查和更新之类的操作。
罗恩·莫平

7

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

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

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

随附的图显示了多个连接(建立了许多连接以每个连接发送一个对象)和持久连接(建立了一个连接并在其中发送了多个对象)之间的区别:

多重连接与持久连接

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


7
这个答案似乎令人困惑。HTTP请求/响应很少是单个数据包。
Barmar

2
更不用说每个“打开”实际上是3个箭头(syn,synack,ack),每个“关闭”是另外4个箭头(fin,ack 2x服务器和客户端),因此,如果每个数据包实际上有一个连接,那么开销很快就会加起来。
htmlcoderexe

5

您对TCP的工作方式的解释是正确的。

至于您的朋友所说的,我在这里看到两种可能性:

  1. 您误解了您的朋友,他指的是某些应用程序层限制,导致每条消息都通过新连接发送(这不一定是不寻常的;取决于哪种软件,可能或不可能决定这种行为)您正在使用的堆栈);

  2. 你的朋友错了。


5

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

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

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

最后,就像其他人提到的那样,TCP是面向流的。没有任何框架。仅仅因为一个对等方以特定的方式写入数据(例如1 1024字节的写入调用,后跟2 256字节的写入调用),这并不能保证另一对等方将以相同大小的块读取数据(例如,它可能会获得全部1536字节)在一次阅读通话中)。因此,如果要通过原始TCP套接字发送多个“消息”,则必须提供自己的成帧协议来描绘不同的消息。尽管当然有简单的方法可以做到这一点,但是通常不建议这样做,因为有许多基于TCP的协议可以解决此问题。有关更多讨论,请参见:https : //blog.stephencleary.com/2009/04/message-framing.html


2

我认为您的朋友在谈论HTTP,而不是TCP。

HTTP最初是无状态协议:每个HTTP请求将使用单独的TCP连接。这就是为什么我们需要cookie(或类似的东西)来实现会话的原因。


0

您已经提到“单个连接,每次都需要一个新端口”,我将解释为您有许多客户端在同一网络环境中使用PAT技术来连接到组织外部的服务器。PAT的限制为65535(IPv4地址的TCP会话限制)。如果为真,则有限制。

TCP是否为每个发送的数据包打开一个新连接?否,只要TCP会话有效就不会。还有...


0

我喜欢TCP上出色的Wikipedia页面。它清楚地显示了端口号发生的情况。偶然地,它也包含了有关资源使用的有用章节:

资源使用

大多数实现在表中分配一个条目,该表将会话映射到正在运行的操作系统进程。由于TCP数据包不包含会话标识符,因此两个端点都使用客户端的地址和端口来标识会话。每当接收到数据包时,TCP实现都必须在此表上执行查找以查找目标进程。该表中的每个条目都称为传输控制块或TCB。它包含有关端点(IP和端口),连接状态,有关正在交换的数据包的运行数据以及用于发送和接收数据的缓冲区的信息。

服务器端的会话数仅受内存限制,并且可以随着新连接的到达而增长,但是客户端必须在向服务器发送第一个SYN之前分配一个随机端口。在整个会话过程中,该端口始终保持分配状态,并有效地限制了来自每个客户端IP地址的传出连接数。如果某个应用程序无法正确关闭不需要的连接,则客户端可能会耗尽资源,甚至无法从其他应用程序建立新的TCP连接。

简而言之,TCP使用了一个非常有限的资源,即客户端上的端口数(这受TCP标头中端口字段的大小限制,为16位)。

因此,TCP 能够端口用完了,如果一个客户端打开了许多并行的TCP连接,无需关闭它们。只是问题发生在客户端,并且连接是否具有相同或不同的服务器IP地址或服务器端口都没有关系。

在您的设置中,您似乎拥有一个可以处理许多客户端请求的应用程序(这些可能是单个TCP请求,因为您的客户端可能会使用它来将一些事件记录到您的应用程序中,而不会保持它们之间打开的TCP通道),并向您的Kafka代理创建一个新的内部请求(很容易是单个TCP连接如果您选择像这样实现它们)。在这种情况下,瓶颈(就资源而言,而不是性能)将是如果您设法同时从客户端获取大量请求(对您来说没有问题,因为在服务器端,您只需要一个端口即可)所有这些),您就向您的Kafka打开了大量转发请求,而Kafka无法足够快地处理它们,最终导致您同时打开了16位以上的连接。

您是这里的法官;检查您的应用程序,并尝试确定每次是否通过单独的请求连接到Kafka(也许通过某些REST API代理)。如果这样做,并且您有大量的客户,那么您肯定会处于危险之中。

如果您只有少数几个客户端(少于65k),和/或与Kafka浏览器保持单一连接,那么就可以了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.