【发布时间】:2012-05-26 03:01:06
【问题描述】:
首先,我必须问哪个州最好?例如实时 MMORPG 服务器。如果我为每个客户端创建一个线程而不是使用非阻塞套接字怎么办?或者如果我使用一个包含所有非阻塞套接字的线程怎么办?你能解释一下优点吗?
【问题讨论】:
首先,我必须问哪个州最好?例如实时 MMORPG 服务器。如果我为每个客户端创建一个线程而不是使用非阻塞套接字怎么办?或者如果我使用一个包含所有非阻塞套接字的线程怎么办?你能解释一下优点吗?
【问题讨论】:
您的问题值得更长的讨论,但这里有一个简短的答案:
使用非阻塞套接字(在 Windows 上),您有几个选择:
重叠 I/O 将为您提供最佳性能(数千个套接字/进程),但代价是要正确理解和实施最复杂的模型。
基本上,它归结为性能与编程复杂性。
注意
这里更好地解释了为什么使用线程/套接字模型是一个坏主意:
在 Windows 中,创建大量线程非常低效,因为调度程序无法正确确定哪些线程应该接收处理器时间,哪些不应该。这与每个线程的内存开销相结合,意味着您将在操作系统级别耗尽内存(因为堆栈空间)和处理器周期(因为管理线程的开销),而在处理套接字连接的容量不足之前很久.
【讨论】:
我将继续记录在案,对于几乎除了玩具程序之外的任何东西,您当然应该使用非阻塞套接字。
阻塞套接字会导致一个严重的问题:如果另一端的机器(或与它的连接的任何部分)在阻塞调用期间发生故障,您的代码将最终被阻塞,直到 IP 堆栈超时。在典型情况下,大约需要 2 分钟,这对于大多数用途来说是完全不可接受的。 1 中止阻塞调用的唯一方法是终止产生它的线程——但终止线程本身几乎总是不可接受的,因为在它之后清理并回收它的任何资源基本上是不可能的已分配。非阻塞套接字使得在需要时中止调用变得微不足道,无需对发出调用的线程做任何事情。
如果您使用多进程模型, 可以使阻塞套接字工作得很好。在这里,您只需为每个连接生成一个全新的进程。该进程使用阻塞套接字,当/如果出现问题时,您只需终止整个进程。操作系统知道如何清理进程中的资源,因此清理不是问题。但是它仍然存在其他潜在问题:1)您几乎需要一个进程监视器来在需要时终止进程,以及 2)生成一个进程通常比仅仅创建一个套接字要昂贵得多。尽管如此,这可能是一个可行的选择,尤其是在以下情况下:
1. 好吧,从技术上讲,这不是唯一可能的方式,但大多数替代方案都比较难看——更具体地说,我认为当你添加代码以找出问题所在时,并且然后解决这个问题,你可能比只使用非阻塞套接字做了更多的工作。
【讨论】:
recv() 的手册说,如果没有可用的消息,它将在阻塞套接字上阻塞。我相信你只需要在收到之前select() 或poll(),你就不必担心这篇文章提到的任何事情。