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

DinS          Written on 2017/9/14

本文介绍服务器模式之非阻塞+轮询,请确保阅读过《socket概述》。

还有另一种思路解决socket的矛盾。
既然问题出在阻塞上,那么设置成非阻塞不就行了吗?具体而言,不断地去recv,如果有内容就取下来,如果没有就进入下一次while,这样一来就解决了socket的阻塞与执行之间的矛盾。

图片来源:http://blog.csdn.net/hguisu/article/details/7453390

非阻塞模式没用到什么新东西,主要是设计程序运行方式。
设置socket为非阻塞要用到ioctlsocket函数,很简单,注释里会说明。
但是非阻塞模式对编程技巧要求非常高,因为绝大部分recv都会返回错误,所以需要处理好各种错误处理情况。

以下是服务端示例代码:

(大图点这里)

整体代码逻辑是两条线程,主线程不断accept,此处依然是阻塞模式,另一条线程不断while去recv,此处是非阻塞模式。
当有客户端连接后,将其设置为非阻塞,加入向量,这样子线程中可以去遍历向量来recv。如果recv成功就进行相应操作,如果不成功就什么都不做,等待下次轮询。

当然这个示例代码还不够好,一个是使用了vector来装连接socket,所以每次通信完成要手动置为INVALID_SOCKET,换成别的数据结构的话close后直接踢出效率更高。二是只有当客户端发送close内容时才算通信结束,这个需要在客户端那里配合,目前用的客户端没做这个处理。

客户端代码就不展示了,都一样。

运行结果如下:

大图点这里

实现了我们的需求。

小结:

非阻塞模式一共只使用了两个线程,规避了多线程模式的弊端,也没有使用过于复杂的技巧,socket支持数量理论上可以很多。编程思路也很简单,比select要容易理解,但是代价是消耗了大量系统资源,一个是轮询,另一个是while(1)。
while(1)不同于阻塞,select这样的函数阻塞时不会消耗过多系统资源,但是while(1)表示程序一直在运行。
非阻塞模式在某些场合下能够发挥强大的效果。