2012-05-18 174 views
34

起初,我必须问哪个州哪个州最好?例如一个实时MMORPG服务器。如果我为每个客户端创建一个线程而不是使用非阻塞套接字?或者如果我使用一个包含所有非阻塞套接字的线程呢?你能解释我的优点吗?我为什么要使用非阻塞或阻塞套接字?

回答

29

你的问题应该得到一个更长的讨论,但这里是在回答的短刺:

  • 使用阻塞套接字意味着只有一个插座可以在任何一个线程的任何时间(是活动的,因为它会阻止在等待对于活动)
  • 使用阻塞套接字通常比非阻塞套接字更容易(异步编程往往更复杂)
  • 您可以按照您所述创建每个套接字1个线程,但是线程有开销并且效率极低非阻塞解决方案;
  • 与非阻塞套接字,你可以处理客户端的体积大得多:它可以扩展到几十万在一个单一的过程 - 但是代码变得有点复杂

与非阻塞套接字(在Windows上)你有两个选择:

  • 轮询
  • 事件基于
  • 重叠I/O

重叠的I/O会以最好的性能(成千上万的套接字/进程)为代价,而不会成为正确理解和实现的最复杂模型。基本上归结为性能与编程的复杂性。

这就是为什么使用线程/插座模型是一个坏主意一个更好的解释:

在Windows中,创建大量线程的效率非常低,因为调度程序无法正确确定哪些线程应该接收处理器时间,哪些线程不应该。这与每个线程的内存开销相结合意味着,在操作系统级别处理套接字连接之前很久,您将在OS级别耗尽内存(由于堆栈空间)和处理器周期(因为管理线程的开销) 。

+0

如果你在一个80路运行框中,你可以撕裂了数以百计的线程没有问题。 –

+0

@John - 仅仅因为可以创建数百个线程(如果你有足够的内存),这并不意味着这是个好主意。其实这是一个坏主意! –

+9

我的观点,不可否认的是,你不能仅仅在20处画一条任意的线,而是调用超出“坏”的任何线程数。 –

8

我会记录下来的话,对于差不多除了玩具程序之外的任何东西,都应该使用非阻塞套接字作为理所当然的事。

阻塞套接字会导致一个严重的问题:如果在阻塞呼叫期间另一端(或其连接的任何部分)的计算机发生故障,则代码将最终阻塞,直到IP堆栈超时。在一个典型的情况下,大约2分钟,这在大多数情况下是完全不可接受的。阻止该阻塞调用的唯一方法是终止创建它的线程 - 但终止线程本身几乎总是不可接受的,因为在它之后进行清理并回收分配的任何资源实际上是不可能的。非阻塞套接字使得在/如果需要时中止呼叫是微不足道的,没有对发起呼叫的线程做任何事情。

如果您使用多进程模型代替,则可以使阻塞套接口工作良好。在这里,您只需为每个连接创建一个全新的进程。该进程使用阻塞套接字,当/如果出现问题时,您只需要关闭整个进程。操作系统知道如何清理进程中的资源,因此清理不成问题。但它仍然有其他潜在的问题:1)你需要一个进程监视器来在需要时终止进程; 2)产生一个进程通常比创建一个套接字要贵一些。然而,这可能是一个可行的选择,特别是当:

  1. 你正在处理少量的连接的同时
  2. 你通常做广泛的处理对每个连接
  3. 你只处理与本地主机所以你对他们的连接速度快且可靠
  4. 你更关心的不是执行

优化开发3210

1.嗯,在技术上不是只有可能的方式,但大多数的替代品相对丑陋 - 更具体地说,我认为当你添加代码,以确定有问题,然后解决这个问题,你可能做了比使用非阻塞套接字更多的额外工作。

+6

可以通过将套接字从另一个线程上下文断开而终止阻塞的套接字操作而不终止阻塞的线程。这将导致被阻止的操作失败,并显示错误代码,然后被阻塞的线程可以继续并执行其他操作,如正常清理。 –