44

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

4

2 回答 2

38

您的问题值得更长的讨论,但这里有一个简短的答案:

  • 使用阻塞套接字意味着在任何一个线程中任何时候都只能有一个套接字处于活动状态(因为它在等待活动时会阻塞)
  • 使用阻塞套接字通常比非阻塞套接字更容易(异步编程往往更复杂)
  • 如您所述,您可以为每个套接字创建 1 个线程,但与非阻塞解决方案相比,线程有开销并且效率极低;
  • 使用非阻塞套接字,您可以处理更多的客户端:它可以在单个进程中扩展到数十万个 - 但代码变得有点复杂

使用非阻塞套接字(在 Windows 上),您有几个选项:

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

重叠 I/O 将为您提供最佳性能(数千个套接字 / 进程),但代价是要成为正确理解和实现的最复杂的模型。

基本上它归结为性能与编程复杂性。

笔记

这里有一个更好的解释为什么使用线程/套接字模型是一个坏主意:

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

于 2012-05-18T14:19:36.623 回答
10

我将继续记录在案,除了玩具程序之外的几乎任何东西,您当然应该使用非阻塞套接字。

阻塞套接字会导致一个严重的问题:如果另一端的机器(或与它的连接的任何部分)在阻塞调用期间发生故障,您的代码将最终被阻塞,直到 IP 堆栈超时。在典型情况下,大约需要 2 分钟,这对于大多数用途来说是完全不可接受的。中止阻塞调用的唯一方法1是终止产生它的线程——但终止线程本身几乎总是不可接受的,因为在它之后清理并回收它分配的任何资源基本上是不可能的。非阻塞套接字使得在需要时/如果需要中止调用变得微不足道,而无需对进行调用的线程做任何事情。

如果您改用多进程模型,则可以使阻塞套接字工作得很好。在这里,您只需为每个连接生成一个全新的进程。该进程使用阻塞套接字,当/如果出现问题时,您只需终止整个进程。操作系统知道如何清理进程中的资源,因此清理不是问题。但是它仍然存在其他潜在问题:1)您几乎需要一个进程监视器来在需要时终止进程,以及 2)产生一个进程通常比仅仅创建一个套接字要昂贵得多。尽管如此,这可能是一个可行的选择,尤其是在以下情况下:

  1. 您一次处理少量连接
  2. 您通常对每个连接进行大量处理
  3. 您只与本地主机打交道,因此您与它们的连接快速且可靠
  4. 你更关心优化开发而不是执行

1. 好吧,从技术上讲不是唯一可能的方法,但大多数替代方案都比较难看——更具体地说,我认为当你添加代码找出问题所在,然后解决问题时,你'与只使用非阻塞套接字相比,你可能做了更多的额外工作。

于 2012-05-18T15:25:36.543 回答