【问题标题】:What is a good way to connect multiple clients to the server?将多个客户端连接到服务器的好方法是什么?
【发布时间】:2010-12-29 19:48:10
【问题描述】:

由于将多客户端连接到服务器有多种方法,例如:fork、select、线程等。如果您能描述将多个客户端连接到服务器的更好方法,我会很高兴?

【问题讨论】:

  • 谢谢!再看问题,我修改了一下...

标签: c++ c networking sockets network-programming


【解决方案1】:

Unix Network Programming 的第 30 章介绍了客户端/服务器设计的替代方案。 UNP 书籍是网络编程的最佳起点。

【讨论】:

    【解决方案2】:

    如果您使用的是 Windows,那么处理大量客户端的最有效方法是围绕异步 I/O 和 I/O 完成端口构建您的服务器。这些允许您以有效的方式使用少量(4?)线程为大量(成千上万)客户端提供服务。

    有些人发现 I/O 完成端口模型的异步特性有点难以理解,但我有一个免费的 C++ 源代码框架,您可以从 here 下载它来帮助您入门。如果您使用托管代码,那么 .Net 框架中的所有异步套接字 API 都“在后台”使用 I/O 完成端口。

    I/O 完成端口模型可以很好地扩展,因为它是一种操作系统原语,从头开始构建以提高效率;它知道与其关联的线程是在运行还是在等待,因此可以管理它允许同时处理“完成”的线程数。它还以 fifo 顺序使用线程,因此如果要做的工作很少,那么浪费的上下文切换就会更少,因为只会使用最少数量的线程(而不是在所有线程中调度工作项并导致它们的所有堆栈保持分页到内存中)。相反,您自己的线程池必须效率较低,因为您没有与 IOCP 相同的线程知识水平。 Select 通常会受到它可以支持的套接字数量的限制,这意味着要获得真正的可伸缩性,您需要在 select 之上构建一些复杂的代码,以便能够管理超过这个数量的客户端。每个连接模型使用一个线程的效率要低得多,因为不仅新线程会定期启动和停止,而且您在任何时候都无法控制进程中的线程数 - 当您考虑时,线程是相对重量级的资源在他们的堆栈空间等。一旦你拥有比 CPU 内核更多的线程,你将在上下文切换中浪费时间(IOCP 通常会完全避免这种情况)。最后,每个连接分叉一个新进程比每个连接模型的线程更重,我个人认为没有任何理由认为这是现代操作系统上的有效选项。

    【讨论】:

      【解决方案3】:

      至少有两种选择。

      • 创建一个监听套接字。
      • 等待连接。
      • 产生一个线程来处理连接。

      • 创建一个监听套接字并使用 select() 等待它。
      • 如果侦听套接字 fd 变为活动状态,则建立新连接并将新 fd 添加到 select 调用中。
      • 如果连接 fd 变为活动状态,请处理它。

      如果您了解线程,则第一种选择可能是一种更简洁的方法。第二种方法需要一些 fd 管理(例如侦听或连接),但可以在单个线程中完成。

      what do you mean by this <<the first alternative might be a cleaner approach>>? can you explain pls?
      

      如果您了解线程和线程之间的同步,则第一种方法可能更简单,因为您可以对连接套接字使用正常的阻塞读取和写入。

      如果您希望能够同时处理所有客户端,则第二种方法要求您使用非阻塞读/写并处理部分数据包。

      【讨论】:

      • 我了解线程并在不同的操作系统上使用它们。抱歉,我认为您不在主题范围内...问题不是关于套接字,而是关于将多个客户端连接到服务器
      • 对不起,也许我没有说清楚。我正在描述让服务器处理多个客户端的两种方法。我过去都使用过它们。
      • 你说的这个>是什么意思?你能解释一下吗?
      【解决方案4】:

      查看C10K 页面,了解 I/O 框架和策略的概览和比较。

      【讨论】:

        【解决方案5】:

        如果您的程序在 Windows 上运行。完全避免线程和进程,并使用套接字编程的异步模型。这是迄今为止进行网络通信的最有效(也是最简单的方法)。

        【讨论】:

        • 谢谢!您能否解释一下如何在 Windows 上异步套接字以及为什么线程无用...
        【解决方案6】:

        一个简单的建议,避免使用 fork,因为它创建了一个重量级的进程,而是使用更轻的线程,并且与当时创建的进程共享相同的内存空间。

        【讨论】:

        • 这取决于操作系统。在 UNIX 上,fork() 和进程是高效的。此外,线程之间共享的地址空间可能会导致非常难以产生错误。综上所述,进程和线程各有利弊。
        • 谢谢!我知道 Windows 不支持 fork() 有效
        【解决方案7】:

        我知道在 C 中 fd_select 提供了这种轮询套接字的能力。不确定,但我猜 C# 有更好的方法。

        【讨论】:

        • 谢谢!你能解释一下是什么意思吗
        【解决方案8】:

        设计一些心跳循环,它将遍历所有套接字并响应它们各自的事件。

        我建议服务器是被动的(客户端将连接到它,而不是服务器连接到客户端),因为它通常在 Web 上完成。因此,它也会有一个监听套接字。

        【讨论】:

        • 心跳循环是个坏主意。因为它意味着检查之间的强制睡眠(也许你有别的想法,在这种情况下忽略这个)。已经有一个 API 可以在一组套接字上等待数据。查看“linux.die.net/man/2/select
        • 还有 Linux 上的 epoll,BSD/MacOSX 上的 kqueue 等等 :)
        • @martin,你在一组套接字上等待,然后你检查所有列表,看看哪些得到了事件。
        • 这不在主题范围内。这不是关于套接字,而是关于处理多个客户端
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-17
        • 1970-01-01
        • 2015-01-20
        • 2012-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多