我正在开发一个应用程序,其中服务器需要与很多简单的物联网设备。服务器和每个设备之间几乎不需要信息交换,但设备需要保持在线并 24 小时可被服务器访问。在某些时候(这种情况很少发生),服务器需要能够与其中一个设备取得联系并交换一些消息:然而,至关重要的是,这些设备必须在很短的时间内可访问。
这意味着我需要这些客户端设备以某种方式持续连接。现在,我想知道:是否可以通过 TCP 连接这些设备并保持这些连接处于活动状态以随时准备交换消息?
我尝试阅读了各种内容,但得到的答案总是相同:这取决于你的实现,因为你的消息交换和处理很可能成为瓶颈,而不是保持这些 TCP 连接处于活动状态。现在,我的情况并非如此,因为我只需要每天交换非常有限的信息很多的时间。
那么,仅让这些客户端保持连接是否合理?还是我应该设计一种更有效的方法?例如,仅保持 TCP 连接而不进行任何数据交换需要多少带宽?这是否需要大量内存或 CPU?
我实现了一个简单的 C++ 程序,每隔几秒向我的服务器发送一次 UDP 保持活动:根据我的基准,即使在相当有限的服务器上,这也可以毫无问题地扩展到数百万个在线设备。 TCP 的性能会比这更差吗?
答案1
至于我对 TCP 的理解,断言“保持 TCP 连接活跃“具有误导性,因为不TCP 协议特定的处理超时的机制,当提到已确立的连接。我的意思是:一旦建立,它们就可以永远持续下去,直到发生 RESET、FIN 或接收 ACK 超时(...在最后一种情况下,是在某些传输被确认之后)。
就我的经验而言,100%的“由于空闲超时而突然中断“这类问题取决于两个通信主机之间的路由路径上的某个中间路由器/防火墙。我的意思是:由于防火墙通常是一个“状态”防火墙,它会跟踪它正在防火墙/管理的连接。因此,它需要跟踪的每个连接都意味着要消耗一定程度的系统资源(我的意思是防火墙的资源)。此外,由于防火墙本身的性质(它是一个有状态的防火墙!)。因此,许多(全部?)防火墙实现都定义了超时,并且如果托管连接在这样的超时值内处于空闲状态,则防火墙会向两端(... TCP 连接的两端)发送重置并释放自己的资源。
根据您的问题,我敢打赌,TCP 连接将由您的 IoT 设备(充当客户端)而不是您的控制服务器(TCP 服务器)打开。因此...很多, 如果不全部,将对您的 IoT 设备流量进行 NAT 的 ADSL 家用路由器肯定会按照描述的方式运行。
至少根据我自己的经验是这样。
但我不是乔恩·波斯特尔,如果我错了,请不要责怪我:-)
附注:你写道“...大量简单的物联网设备...“。请记住,使用单个大型服务器可以处理的并发 TCP 连接数有非常严格的限制。TCP“端口”是 16 位值。因此,对于每个 IP 地址,您不能超过(根据 TCP 固有设计)64K 个连接。如何解决这个问题,超出了这个问题的范围。
最后,让我补充一点,我确实看到不在物联网设备和管理服务器/应用程序之间实现某种心跳协议是一个问题。它可以实现得非常“网络友好”,对带宽没有影响,并且很多在可管理性/控制方面具有优势。
答案2
您的想法很好;事实上,现代移动设备对通知使用完全相同的方法,它们与操作系统开发人员的服务器保持永久连接,该服务器通过该连接推送通知(第三方应用程序开发人员将通知发送给操作系统开发人员,操作系统开发人员再将其转发到适当的移动设备)。
如果您的设备保证具有可公开路由的 IP 并且能够监听套接字,则可以使用另一种方法;在这种情况下,设备将在每次 IP 更改时通知您的服务器,但每当您的服务器需要向设备提供某些数据时,服务器都会连接到设备的套接字并向其发送数据。这样,您的服务器就不需要处理任何负载,只需在其数据库中更新每个设备的 IP 地址并偶尔连接到设备并向其发送数据即可。
关于 TCP 与 UDP,我认为 TCP 更能保证设备的可达性 - 使用 TCP,只要连接打开,就可以保证设备仍然在那里(否则连接将超时)。使用 UDP,您只是将数据包抛向空中,甚至不知道它们是否到达目的地(除非您实现自己的保持活动、连接管理和重新传输系统,但是当您已经有一个名为 TCP 的可靠且流行的实现时,为什么还要重新发明轮子呢?)。您还必须考虑防火墙和 NAT,使用 TCP 一旦建立连接,您就可以确保发送的任何内容都能到达目的地,而使用 UDP 则不能那么确定,并且必须以不同程度的成功率打洞。