C++ winsock服务器中非阻塞模式与异步套接字的区别

Posted

技术标签:

【中文标题】C++ winsock服务器中非阻塞模式与异步套接字的区别【英文标题】:Different between none-blocking mode with async socket in C++ winsock server 【发布时间】:2012-06-27 05:06:36 【问题描述】:

在 C++ 中,我阅读了一些教程来创建一个可以接受来自多个客户端的连接的服务器。他们建议使用异步套接字,但我真的不知道为什么我们应该选择异步而不是非阻塞模式。使用多线程的想法又是怎样的呢?它比使用异步套接字更好吗?谢谢!!

【问题讨论】:

这很大程度上取决于整个应用程序的设计。如果它已经是异步/事件驱动的,那么使用异步套接字可能是最好的,如果它已经有自己的事件循环或轮询,那么使用带有轮询的非阻塞套接字可能是最好的,如果你想接收连接然后“忘记”关于他们(很像一个网络服务器)然后线程将运行良好。 作为我的评论的附录,关于线程......当连接彼此独立并且不需要与其他连接和/或主线程通信时,它们会很好。 如果您使用线程,那么您可以更进一步,使用 IOCP 减少所需的线程数,同时增加您可以处理的连接数。与主线程通信并不是避免线程化连接的理由。大多数套接字逻辑不需要访问主线程,因此它会从线程中受益。主线程访问应该是小操作,所以不会使线程非常慢。 【参考方案1】:

由于您要求使用 C++ 解决方案,boost asio 是 imo 最好的异步 io 库。

我假设您在提到“多线程”时谈论的是“每个客户端一个线程”解决方案,这对于希望在短时间内有多个客户端或同时连接的服务器来说通常是一个非常糟糕的主意时间。 线程是这种用途的资源消耗方式,而且您必须注意互斥,这与阻塞调用相结合会使您很快陷入死锁。这是您可能遇到的最糟糕的情况。

此外,攻击者很容易利用您的服务器卡住。您将花费大量时间来尝试设计您的代码,以避免这种情况发生,这会导致您的代码不可读、难以更新和出错。

在 boost.asio 中,指定的线程(调用 io_service::run 的线程)只有在实际有工作要做时才会工作,直接引导您进入分配给任务的对象。 因此,从技术上讲,异步也是阻塞的,不同之处在于只有调度程序等待工作完成,而您添加的那些功能(连接、发送、接收......)将立即返回。

【讨论】:

为什么坚持一个客户端一个线程的服务器比任何其他类型的服务器都容易?如果一个客户端处理程序线程确实卡住了,那又如何呢?如果异步服务器上的一个线程卡住了,那就告别所有客户端。异步客户端代码是一个状态机,而不是易于进行的简单内联调用。每个客户端一个线程并不意味着“不可读、难以更新和错误电话代码”,它只是可以进行阻塞调用的内联代码。如果您需要 10 秒的暂停,请使用 Sleep(10000) - 没问题。在异步处理程序中尝试! @MartinJames:每个客户端一个线程的服务器也是一个每个客户端一个堆栈的服务器。默认大小为兆字节,因此 2000 个连接为 2GB。即使假设有足够的物理内存,这也是缓存的噩梦,在 32 位操作系统上,地址空间不足——打开 2000 个连接,然后什么都不做……砰,你死定了。我什至没有谈论处理数千个线程的调度程序负载。在单线程状态机上,同样是 10-20kB 的数据加上 IOCP 内的另外 10-20kB。只要电线上没有任何事情发生,零动作。 总的来说,我同意带有状态机的 ASIO/IOCP 服务器更具可扩展性,也更复杂。上次我使用 IOCP 时,您必须为在其链接套接字对象中接收到的每个完成实例添加一个序列号,以防止池线程对缓冲区的无序处理。对于每个客户端一个堆栈,1 MB 太大 - 将其设置为 128K。不必有物理 RAM - 用户堆栈是可交换的。数千个未就绪线程的调度程序负载为零 - 没有什么可调度的 - 所以只要线路上没有任何事情发生,零操作。 没有未就绪列表。有一个就绪线程队列的数组[优先级],并且在任何更改此结构的内容的硬件/软件中断之后,调度程序通过从最高优先级轮询队列的头部来获取 [核心数量] 线程。向下。未就绪的线程也在队列中 - 反对他们正在等待的信号。对象等待队列的长度无关紧要,因为操作系统只需要头部条目。 ..而且,在臭名昭著的“tick/quantum”中断上,操作系统只需将就绪队列的尾部旋转到头部,因此实现了一些开发人员的“循环”调度似乎认为是常态 :( 如果你想试试这个,写一个简单的应用程序,只创建,比如说,3000 个睡眠线程(无限)。运行它,然后继续使用你的盒子,看看它是多么无响应。结果会正常运行。【参考方案2】:

我假设您说的是 TCP 而不是 UDP。我绝对推荐 skipping 异步套接字,它们受到 Microsoft 和支持者的青睐,但不可移植。而是使用普通的东西:here's an example 与 server 和 client。

【讨论】:

以上是关于C++ winsock服务器中非阻塞模式与异步套接字的区别的主要内容,如果未能解决你的问题,请参考以下文章

Select模型

阻塞与非阻塞winsock的速度/性能特征

C++ winsock 错误

服务器套接字只能连接几次(Winsock C++)

如果 winsock2 套接字是非阻塞的,与之关联的 SSL 对象是不是也会表现出非阻塞行为?

winsock c++中recv函数的奇怪行为