大量连接时应选择TCP还是UDP?

3
我想创建一个具有以下特点的P2P网络:
  • 低延迟并不是非常重要
  • 丢包是可以接受的
  • 节点只会在周围发送少量数据
  • 不会出现NAT/防火墙问题,每个节点都有一个公共IP上的开放端口
  • 每个节点都连接到其他每个节点
通常情况下,我会使用TCP处理非时间关键性的事务,但最后一个要求导致节点需要长时间拥有大量的打开连接。如果我记得正确,使用TCP连接到1000个服务器意味着我必须使用1000个端口来处理这些连接。另一方面,UDP仅需要每个节点一个端口。
因此,我的问题是:在具有例如1000个节点的网络中,TCP是否能够处理以上要求而无需调整系统?在这种情况下,UDP是否更适合?还有其他任何可能成为协议障碍的问题吗?

这不是一个真正的编程问题。这是一个架构设计问题,可能也是一个网络问题。它可能适合在程序员或其他地方讨论,但目前写的内容不在我们帮助中心定义的范围内。 - Todd A. Jacobs
1
建议查看TCP vs UDP进行比较。将其与您的特性列表进行比较并做出选择。UDP很可能是最合适的选择。 - Jonathon Ogden
3个回答

3
使用UDP,您可以控制“连接状态”,这几乎是进行任何点对点相关操作的最佳方式,如果您拥有大量节点或关心带宽、内存和CPU开销。通过将所有与每个节点的“连接状态”相关的控制移动到您的应用程序中,您可以最小化浪费资源的数量,使其完全符合您的需求。
您将绕过许多特定于操作系统的怪异问题,这些问题限制了TCP在高连接数下的有效性。 TIME_WAIT膨胀和数十到数百个需要为每个P2P应用程序用户进行调整的特定于操作系统的设置。我制作的一个测试应用程序允许您使用带有确认或TCP的UDP,无论使用UDP的操作系统如何,性能差异仅有10%。 TCP的性能始终低于最佳UDP,其性能变化范围高达600%,具体取决于操作系统。通过调整,您可以使大多数操作系统使用TCP大致相同,但默认情况下,大多数操作系统没有正确调整。
因此,在我看来,与TCP相比,创建可靠的UDP P2P网络更加困难,但通常是必要的。但是,我只建议您采用这种方法,如果您在网络方面非常有经验,因为有许多需要处理的“陷阱”。有一些库可以帮助处理此类问题,例如Raknet或Enet。它们提供了使用可靠的UDP的方法,但仍需要更高的网络知识才能知道所有这些内容如何相互关联,而对于TCP,大部分都是隐藏的。
在点对点网络中,您经常会收到像NODE PING这样的消息,您可能并不关心每个消息是否始终被接收,您只关心最近是否收到过一条消息。也就是说,您可以每10秒发送一次ping,并在60秒内未收到ping后断开该节点。这意味着您需要连续6个ping数据包失败,这是极不可能发生的,除非该节点真的已关闭。如果在该60秒期间收到了至少一个ping,则该节点仍处于活动状态。如果使用TCP实现这一点,则会涉及更多的延迟和带宽,因为它确保每个ping消息都通过,并将阻止任何其他数据出去,直到它通过。由于您不能依赖TCP可靠地告诉您连接是否已断开,因此您被迫添加类似的PING功能以用于TCP,除了TCP已经在处理数据包的所有其他额外事项之外。
游戏通常还有一些数据,如果客户端没有接收到它,那么没有关系,因为几毫秒后会有更多的数据包到来,这将使任何遗漏的数据包无效。也就是说,玩家在1秒钟内从A移动到Z,他的客户端每40毫秒发送一次更新,ABCDEF G__I__KLMNOPQRSTUVWXYZ。如果我们错过了“H和J”,是否真的很重要?不太重要,这就是预测可以发挥作用的地方,但这通常与大多数P2P项目无关。如果那是TCP而不是UDP,则会增加带宽要求,并为接收到的其他数据包添加延迟,因为数据将被重新发送,直到它到达,除了它已经通过确认添加的额外延迟。
基本上,你可以使用UDP降低点对点网络中许多消息的延迟和网络开销。然而,总会有一些消息是需要可靠发送的,这就要求你基本上实现一些可靠的方式将数据包发送到该节点,类似于TCP。如果你想要一个可靠的点对点网络,那么你需要一定的专业知识。一些需要研究的事情包括用数字排序数据包、消息ACK等。
如果你非常关心效率或者确实需要成千上万的连接,那么在UDP中实现你的特定协议总是比TCP更好。但是也有TCP的使用场景,比如如果项目的时间很重要,或者你是网络编程的新手。

2
如果我没记错的话,使用TCP连接到1000个服务器意味着我必须使用1000个端口来处理这些连接。
你记错了。以监听端口80并可以同时处理数千个连接的Web服务器为例。这是因为连接由{client-ip, client-port, server-ip, server-port}元组定义。虽然对于所有连接到此服务器的连接,server-ip和server-port相同,但client-ip和client-port不同。即使client-ip相同(即相同的客户端),客户端也会选择不同的源端口。
...例如使用1000个节点而无需调整系统?
这取决于系统,因为每个打开的连接都需要保留状态,因此需要内存。这可能对只有少量内存的嵌入式系统造成问题。
在任何情况下:如果您的协议仅发送小消息,并且数据包丢失、重排序或重复是可接受的,则UDP可能是更好的选择,因为开销(连接设置、ACK等)更小且占用的内存更少。您还可以使用单个套接字与所有1000个节点交换数据,而使用TCP则需要为每个连接使用单独的套接字(套接字与端口不同!)。仅使用单个套接字可能允许更简单的应用程序设计。

TCP仍然可能出现“端口耗尽”的情况。如果您只有一个侦听套接字,则理论上每个远程IP地址的限制为65535。通常情况下,这个数字要少得多,Windows在过去有设置将其限制在约5000个。再加上操作系统部分处理TIME_WAIT不佳,您很容易发现特定远程IP地址的端口已用尽。我曾在高吞吐量的前端看到过这种情况,该前端连接到单个后端。但是,对于像问题中的P2P应用程序来说,这不应该是一个问题。 - Ryler Sturden

1
我希望通过以下几点来修改Steffen的答案:
  1. 对于任何普通的计算机和操作系统来说,1000个连接都不是问题。
  2. UDP符合您的要求。它可能更容易编程,因为它是面向消息的。TCP提供字节流。您需要在其上分层一个消息协议,这并不容易。此外,您需要通过重新连接来处理断开的TCP连接。
  3. 端口不是稀缺资源。使用1000个端口没有问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接