【问题标题】:Most efficient way to handle a client connection (socket programming)处理客户端连接的最有效方法(套接字编程)
【发布时间】:2012-07-26 02:20:04
【问题描述】:

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

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

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

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

【问题讨论】:

  • 大多数(无论如何都是高效的,即不包括创建/终止/加入),线程代码被编写为无限循环,在顶部某处有一个阻塞调用。别担心 :)

标签: c++ c linux sockets unix


【解决方案1】:

对于 C++,您可以查看 boost.asio。您也可以查看例如asynchronous I/O 函数。还有SIGIO

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

【讨论】:

    【解决方案2】:

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

    accept() 视为对join() 的调用或对互斥锁/锁/信号量的等待。

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

    【讨论】:

    • 没错。从操作系统的角度来看(特别是针对 Linux),当您在进程中调用 accept()(阻塞调用)并且没有传入连接时,您的进程进入睡眠状态:它的状态从 TASK_RUNNING 更改为 TASK_(UN)INTERRUPTIBLE 并且它已附加到内核​​的等待队列之一。然后调用调度程序来选择下一个要运行的进程——因此从操作系统的角度来看,不会浪费任何处理时间。当新的连接请求到达时,您的进程将被唤醒。
    【解决方案3】:

    无限循环是为了维持服务器的运行状态,所以当一个客户端连接被接受时,服务器不会立即退出,而是会回到监听另一个客户端连接。

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

    【讨论】:

    • 第二段大多不正确。 listen() 不等待,也不接收数据。 accept() 等待但它也不接收数据,它接收连接。这不是通过硬件中断或网络驱动程序完成的,而是通过 TCP/IP 堆栈和积压队列完成的。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      这里很好地概述了可用的技术 - The C10K problem

      【讨论】:

        【解决方案6】:

        除了已经发布的内容之外,使用调试器很容易看到正在发生的事情。在执行 accept() 行之前,您将能够单步执行,此时“单步”突出显示将消失,应用程序将继续运行 - 未到达下一行。如果您将面包点放在下一行,则在客户端连接之前它不会触发。

        【讨论】:

          【解决方案7】:

          我们需要遵循编写客户端-服务器程序的最佳实践。目前我可以向您推荐的最佳指南是 The C10K Problem 。在这种情况下,我们需要遵循一些特定的东西。我们可以选择使用 select 或 poll 或 epoll。各有优缺点。

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

          如果您使用 select、poll、epoll,那么您将被阻塞,直到您获得事件/触发器,这样您的服务器就不会因消耗系统时间而陷入无限循环。

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

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

          【讨论】:

            猜你喜欢
            • 2014-01-22
            • 1970-01-01
            • 2015-02-08
            • 2023-03-03
            • 1970-01-01
            • 1970-01-01
            • 2013-02-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多