2009-12-24 96 views
4

由于有多种连接多客户端到服务器的方式,例如:fork,select,threads等。如果能描述哪个更好地将多个客户端连接到服务器,我会很高兴。将多个客户端连接到服务器的好方法是什么?

+3

你能更具体吗? – Andres 2009-12-24 13:45:21

+0

谢谢!再次看到问题,我修改了它... – make 2009-12-24 14:12:50

回答

6

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

+0

感谢您的链接。这很有趣 – make 2009-12-24 15:25:04

+0

优秀的网页! – 2009-12-24 18:54:23

4

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

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

+1

心跳循环是一个坏主意。因为它意味着支票之间的强迫睡眠(也许你有其他的想法,在这种情况下忽略这一点)。已经有一个API等待一组套接字上的数据。看看'http://linux.die.net/man/2/select' – 2009-12-24 18:17:00

+0

和Linux上的epoll,BSDs/MacOSX上的kqueue等等:) :) – 2009-12-24 19:47:26

+0

@martin,你等一组套接字,但是你查看所有列表并查看获得的事件。 – 2009-12-24 19:58:13

1

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

+0

谢谢!你能解释一下你的意思是什么?“轮询插座的能力.. – make 2009-12-24 15:26:51

2

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

+0

这取决于操作系统。在UNIX上,fork()和进程是有效的。线程之间共享的地址空间也会导致很难产生错误。总之,流程和线程都有优点和缺点。 – 2009-12-24 14:13:17

+0

谢谢!我知道fork()在Windows上不受支持 – make 2009-12-24 21:53:02

2

至少有两个选项。

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

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

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

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

如果你理解了线程和线程之间的同步,第一种方法可以更简单,因为你可以使用正常封闭读取和写入连接插座。

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

+0

我理解线程并在不同的操作系统上使用它们。对不起,我认为你已经不在话题了......问题不是关于套接字,而是关于将多个客户端连接到服务器 – make 2009-12-24 14:08:57

+0

对不起,我没有把自己弄清楚。我正在描述两种方式让服务器处理多个客户端。我过去都用过它们。 – 2009-12-24 14:11:13

+0

这是什么意思?“第一种选择可能是更清洁的方法”?你能解释一下吗? – make 2009-12-24 14:20:32

1

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

+0

谢谢!你能否解释一下如何在Windows上使用异步套接字以及为什么线程无用...... – make 2009-12-24 21:55:43

1

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

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

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

+0

非常感谢回复 – make 2009-12-24 22:33:28

相关问题