asio服务器模式:多线程或轮询

DinS          Written on 2017/10/29

本文讲解如何使用asio搭建服务器模式,请确保阅读过《asio基础使用方法》和《标准库多线程编程 – 基础》。

一、服务器模式:阻塞+多线程模式

下面我们来使用asio实现阻塞+多线程模式。
客户端代码如下:

(大图点这里)

整体逻辑很清晰,while中不断accept阻塞,如果有连接就开一个新线程处理。
得益于c++11提供的thread,我们不再需要全局变量来保存连接socket,这样免去了许多麻烦事,不过造成的结果是开辟线程那一句代码有些费解,出现了move和detach。
如果不深究,照着写即可。不加move和detach会报错。
如果深究,那么move是c++11中的移动语义。如果不加编译通不过,会链接到boost库。以后凡是遇到要把socket类作为值传递时,都需要加move()。
detach是把子线程与calling thread分离,二者从此断绝关系。不加detach编译可以过,但是运行时创建新线程会崩。
总之这个是Asio给出的示例写法,照着写就没什么问题。

运行结果:

成功实现了多对一响应。

二、服务器模式:非阻塞+轮询

使用Asio可以很方便地实现非阻塞模式,而且更为神奇的是我们并不用设置socket为阻塞或者非阻塞。
Asio的socket类提供了一个available函数,可以返回可供读取的字节数,这样我们直接调这个函数就够了。真是方便的抽象。

来看服务端代码:

(大图点击这里)

整体思路跟socketAPI是一致的,主线程不断accept,这是阻塞操作。如果有连接就加入list。这里使用的是list而不是vector,这是为了方便动态增删socket。
另外开一个线程不断遍历list,使用available判定socket,如果发现socket已就绪就recv和send。通信结束后移除list。得益于list的性质只需要O(1)时间。如果发现没有就绪,就查下一个。
因为使用了available,我们并没有把socket设置为非阻塞一样达到了目的。
Asio确实好用。

下面看一个远程环境中的例子:

服务器上运行服务端显示的内容。从内容上看可以推测出打开客户端的顺序,以及每个客户端说了什么。非阻塞和list的设计都成功了。

三、小结

使用asio做多线程或轮询模式都异常简单明了。然而这些并非asio的核心,所谓asio指的是asynchrous i/o,所以异步调用模式才是asio真正的强大之处,见《asio服务器模式:异步调用》。