处理客户端连接的最有效方法(套接字编程)



对于我在互联网上看到的Linux/Unix套接字教程的每一个教程和示例,服务器端代码总是包含一个无限循环,每次都会检查客户端连接。示例:

http://www.thegeekstuff.com/2011/12/c-socket-programming/

http://tldp.org/LDP/LG/issue74/tougher.html#3.2

是否有更有效的方法来构建服务器端代码,使其不涉及无限循环,或者以占用更少系统资源的方式对无限循环进行编码?

这些例子中的无限循环已经很有效了。对accept()的调用是阻塞调用:直到有客户端连接到服务器,函数才会返回。调用accept()函数的线程的代码执行被暂停并且不占用任何处理能力。

accept()看作是对join()的调用,或者像是对互斥锁/信号量的等待。

当然,还有许多其他方法可以处理传入连接,但这些其他方法处理accept()的阻塞特性。此功能很难取消,因此存在非阻塞替代方案,允许服务器在等待传入连接时执行其他操作。一种这样的替代方案是使用CCD_ 6。其他替代方案的可移植性较差,因为它们涉及通过回调函数、事件或操作系统处理的任何其他异步机制发出连接信号的低级操作系统调用。。。

对于C++,你可以研究boost.asio。你也可以研究异步I/O函数。还有SIGIO

当然,即使使用这些异步方法,主程序仍然需要处于循环中,否则程序将退出。

无限循环用于维护服务器的运行状态,因此当接受客户端连接时,服务器不会立即退出,而是会重新侦听另一个客户端连接。

listen()调用是一个阻塞调用,也就是说,它一直等到接收到数据。这是一种非常有效的方式,通过使用触发唤醒侦听线程的事件(或硬件中断)的操作系统网络驱动程序,使用零系统资源(当然,直到建立连接)。

下面简要介绍了可用的技术——C10K问题。

当您实现一个监听可能无限连接的服务器时,imo无法绕过某种无限循环。通常这根本不是问题,因为当套接字没有标记为非阻塞时,对accept()的调用将阻塞,直到新连接到达。由于这种阻塞,没有浪费系统资源。

提供类似于基于事件的系统的其他库最终以上述方式实现。

除了已经发布的内容外,还可以很容易地查看调试器的运行情况。您将能够单步执行,直到执行accept()行,在此行上,"sigle step"高亮显示将消失,应用程序将继续运行-下一行未到达。如果在下一行上放置一个breadkpoint,则在客户端连接之前,它不会激发。

我们需要遵循编写客户端-服务器程序的最佳实践。这个时候我能推荐给你的最好的指南是C10K问题。在这种情况下,我们需要遵循一些具体的内容。我们可以使用select、poll或epoll。每个人都有自己的优点和缺点。

如果您使用最新的内核版本运行代码,那么我建议您使用epoll。点击查看示例程序以了解epoll。

如果你正在使用select、poll、epoll,那么你将被阻止,直到你得到一个事件/触发器,这样你的服务器就不会因为消耗系统时间而运行到无限循环中。

根据我的个人经验,我觉得epoll是走得更远的最佳方式,因为我观察到我的服务器机器在拥有80k ACTIVE连接时的阈值在比较它将选择和轮询时非常低。我的服务器机器在拥有80k活动连接时的平均负载仅为3.2:)

在使用轮询进行测试时,我发现当达到30k活动客户端连接时,我的服务器平均负载上升到7.8:(.

最新更新