我为什么要使用非阻塞或阻塞套接字?

时间:2012-05-18 14:15:48

标签: c++ sockets winsock

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

2 个答案:

答案 0 :(得分:33)

你的问题应该进行更长时间的讨论,但这是一个简短的答案:

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

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

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

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

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

注意

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

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

答案 1 :(得分:11)

我会记录说,对于几乎除玩具程序之外的任何东西,你当然应该使用非阻塞套接字。

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

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

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

  5. 1.好吧,技术上不是唯一可能的方式,但大多数替代方案相对比较丑陋 - 更具体一点,我想当你添加代码来弄清楚那里有什么?问题,然后解决问题,你可能比只使用非阻塞套接字做了更多的额外工作。