C++ 为什么要使用非阻塞或阻塞套接字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10654286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why should I use non-blocking or blocking sockets?
提问by deniz
At first, I must ask that which is the best in which states ? For example a real-time MMORPG server. What if i create a thread per client instead of using non-blocking sockets ? Or What if i use one thread that contains all non-blocking sockets ? Can you explain me the advantages ?
首先,我必须问哪个州最好?例如实时 MMORPG 服务器。如果我为每个客户端创建一个线程而不是使用非阻塞套接字怎么办?或者如果我使用一个包含所有非阻塞套接字的线程怎么办?你能解释一下优点吗?
采纳答案by Mike Dinescu
Your question deserves a much longer discussion but here's a short stab at an answer:
你的问题值得更长时间的讨论,但这里有一个简短的答案:
- using blocking sockets means that only one socket may be active at any time in any one thread (because it blocks while waiting for activity)
- using blocking sockets is generally easier than non-blocking sockets (asynchronous programming tends to be more complicated)
- you could create 1 thread per socket as you stated but threads have overhead and are extremely inefficient compared to the non-blocking solutions;
- with non-blocking sockets you could handle a much larger volume of clients: it could scale to hundreds of thousands in a single process - but the code becomes a little bit more complicated
- 使用阻塞套接字意味着在任何一个线程中任何时候都可能只有一个套接字处于活动状态(因为它在等待活动时阻塞)
- 使用阻塞套接字通常比非阻塞套接字更容易(异步编程往往更复杂)
- 正如您所说,您可以为每个套接字创建 1 个线程,但与非阻塞解决方案相比,线程有开销并且效率极低;
- 使用非阻塞套接字,您可以处理大量客户端:它可以在单个进程中扩展到数十万 - 但代码变得有点复杂
With non-blocking sockets (on Windows) you have a couple of options:
使用非阻塞套接字(在 Windows 上),您有几个选择:
- polling
- events based
- overlapped I/O
- 轮询
- 基于事件
- 重叠输入/输出
Overlapped I/O will give you the best performance (thousands of sockets / process) at the expense of being the most complicated model to understand and implement correctly.
重叠 I/O 将为您提供最佳性能(数千个套接字/进程),但代价是成为最复杂的模型以正确理解和实现。
Basically it comes down to performance vs. programming complexity.
基本上它归结为性能与编程复杂性。
NOTE
笔记
Here's a better explanation of why using a thread/socket model is a bad idea:
这里有一个更好的解释为什么使用线程/套接字模型是一个坏主意:
In windows, creating a large number of threads is highly inefficient because the scheduler is unable to properly determine which threads should be receiving processor time and which shouldn't. That coupled with the memory overhead of each thread means that you will run out of memory (because of stack space) and processor cycles (because of overhead in managing threads) at the OS level long before you will run out of capacity to handle socket connections.
在 Windows 中,创建大量线程的效率非常低,因为调度程序无法正确确定哪些线程应该接收处理器时间,哪些不应该。再加上每个线程的内存开销,这意味着您将在操作系统级别用完内存(因为堆栈空间)和处理器周期(因为管理线程的开销)很久,然后您才能用完处理套接字连接的容量.
回答by Jerry Coffin
I will go on record as saying that for almostanything except toy programs, you should use non-blocking sockets as a matter of course.
我会继续说,对于除玩具程序之外的几乎所有内容,您应该理所当然地使用非阻塞套接字。
Blocking sockets cause a serious problem: if the machine on the other end (or any part of your connection to it) fails during a blocking call, your code will end up blocked until the IP stack's timeout. In a typical case, that's around 2 minutes, which is completely unacceptable for most purposes. The only way1to abort that blocking call is to terminate the thread that made it -- but terminating a thread is itself almost always unacceptable, as it's essentially impossible to clean up after it and reclaim whatever resources it had allocated. Non-blocking sockets make it trivial to abort a call when/if needed, withoutdoing anything to the thread that made the call.
阻塞套接字会导致一个严重的问题:如果另一端的机器(或与它的连接的任何部分)在阻塞调用期间出现故障,您的代码将最终被阻塞,直到 IP 堆栈超时。在典型情况下,这大约是 2 分钟,这对于大多数用途来说是完全不可接受的。中止阻塞调用的唯一方法1是终止创建它的线程——但终止线程本身几乎总是不可接受的,因为在它之后进行清理并回收它分配的任何资源基本上是不可能的。非阻塞套接字使得在需要时/如果需要中止调用变得微不足道,而不会对进行调用的线程做任何事情。
It is possible to make blocking sockets work sort of well ifyou use a multi-process model instead. Here, you simply spawn an entirely new process for each connection. That process uses a blocking socket, and when/if something goes wrong, you just kill the entire process. The OS knows how to clean up the resources from a process, so cleanup isn't a problem. It still has other potential problems though: 1) you pretty much need a process monitor to kill processes when needed, and 2) spawning a process is usually quite a bit more expensive than just creating a socket. Nonetheless, this can be a viable option, especially if:
如果您改用多进程模型,则可以使阻塞套接字工作得很好。在这里,您只需为每个连接生成一个全新的进程。该进程使用阻塞套接字,并且当/如果出现问题时,您只需终止整个进程。操作系统知道如何清理进程中的资源,因此清理不是问题。但是它仍然存在其他潜在问题:1)您几乎需要一个进程监视器来在需要时终止进程,并且 2)生成一个进程通常比仅仅创建一个套接字要昂贵得多。尽管如此,这可能是一个可行的选择,尤其是在以下情况下:
- You're dealing with a small number of connections at a time
- You generally do extensive processing for each connection
- You're dealing only with local hosts so your connection to them is fast and dependable
- You're more concerned with optimizing development than execution
- 您一次处理少量连接
- 您通常对每个连接进行大量处理
- 您只与本地主机打交道,因此您与它们的连接既快速又可靠
- 你更关心优化开发而不是执行
1. Well, technically not the onlypossible way, but most of the alternatives are relatively ugly--to be more specific, I think by the time you add code to figure out that there's a problem, and then fix the problem, you've probably done more extra work than if you just use a non-blocking socket.
1. 嗯,技术上不是唯一可能的方法,但大多数替代方案都相对丑陋——更具体地说,我认为当你添加代码以找出存在问题,然后解决问题时,你与只使用非阻塞套接字相比,我可能做了更多的额外工作。