【发布时间】:2010-12-29 19:48:10
【问题描述】:
由于将多客户端连接到服务器有多种方法,例如:fork、select、线程等。如果您能描述将多个客户端连接到服务器的更好方法,我会很高兴?
【问题讨论】:
-
谢谢!再看问题,我修改了一下...
标签: c++ c networking sockets network-programming
由于将多客户端连接到服务器有多种方法,例如:fork、select、线程等。如果您能描述将多个客户端连接到服务器的更好方法,我会很高兴?
【问题讨论】:
标签: c++ c networking sockets network-programming
Unix Network Programming 的第 30 章介绍了客户端/服务器设计的替代方案。 UNP 书籍是网络编程的最佳起点。
【讨论】:
如果您使用的是 Windows,那么处理大量客户端的最有效方法是围绕异步 I/O 和 I/O 完成端口构建您的服务器。这些允许您以有效的方式使用少量(4?)线程为大量(成千上万)客户端提供服务。
有些人发现 I/O 完成端口模型的异步特性有点难以理解,但我有一个免费的 C++ 源代码框架,您可以从 here 下载它来帮助您入门。如果您使用托管代码,那么 .Net 框架中的所有异步套接字 API 都“在后台”使用 I/O 完成端口。
I/O 完成端口模型可以很好地扩展,因为它是一种操作系统原语,从头开始构建以提高效率;它知道与其关联的线程是在运行还是在等待,因此可以管理它允许同时处理“完成”的线程数。它还以 fifo 顺序使用线程,因此如果要做的工作很少,那么浪费的上下文切换就会更少,因为只会使用最少数量的线程(而不是在所有线程中调度工作项并导致它们的所有堆栈保持分页到内存中)。相反,您自己的线程池必须效率较低,因为您没有与 IOCP 相同的线程知识水平。 Select 通常会受到它可以支持的套接字数量的限制,这意味着要获得真正的可伸缩性,您需要在 select 之上构建一些复杂的代码,以便能够管理超过这个数量的客户端。每个连接模型使用一个线程的效率要低得多,因为不仅新线程会定期启动和停止,而且您在任何时候都无法控制进程中的线程数 - 当您考虑时,线程是相对重量级的资源在他们的堆栈空间等。一旦你拥有比 CPU 内核更多的线程,你将在上下文切换中浪费时间(IOCP 通常会完全避免这种情况)。最后,每个连接分叉一个新进程比每个连接模型的线程更重,我个人认为没有任何理由认为这是现代操作系统上的有效选项。
【讨论】:
至少有两种选择。
或
如果您了解线程,则第一种选择可能是一种更简洁的方法。第二种方法需要一些 fd 管理(例如侦听或连接),但可以在单个线程中完成。
what do you mean by this <<the first alternative might be a cleaner approach>>? can you explain pls?
如果您了解线程和线程之间的同步,则第一种方法可能更简单,因为您可以对连接套接字使用正常的阻塞读取和写入。
如果您希望能够同时处理所有客户端,则第二种方法要求您使用非阻塞读/写并处理部分数据包。
【讨论】:
查看C10K 页面,了解 I/O 框架和策略的概览和比较。
【讨论】:
如果您的程序在 Windows 上运行。完全避免线程和进程,并使用套接字编程的异步模型。这是迄今为止进行网络通信的最有效(也是最简单的方法)。
【讨论】:
一个简单的建议,避免使用 fork,因为它创建了一个重量级的进程,而是使用更轻的线程,并且与当时创建的进程共享相同的内存空间。
【讨论】:
我知道在 C 中 fd_select 提供了这种轮询套接字的能力。不确定,但我猜 C# 有更好的方法。
【讨论】:
设计一些心跳循环,它将遍历所有套接字并响应它们各自的事件。
我建议服务器是被动的(客户端将连接到它,而不是服务器连接到客户端),因为它通常在 Web 上完成。因此,它也会有一个监听套接字。
【讨论】: