Socket有两种调用模式:堵塞与非堵塞模式。
顾名思义,堵塞模式就是线程在调用windows socket API后,被挂起直到该函数执行完毕。在(1)中我们知道socket函数调用并不是立即完成的,例如Accept函数,只有当有连接到达时才会执行结束。至于windows是通过什么方式将线程挂起又唤醒的,用户模式同步也好,内核模式同步也好,我们程序员不必关心,给我们程序员的错觉就是程序在以一种同步的方式执行。这种方式编写程序很轻松,但是白白浪费了一个线程,我们程序中的其他逻辑不能得到执行了,除非另起一个线程。
非堵塞模式正好相反,线程在调用Accept函数后,可以继续执行后面的逻辑,线程不会被挂起。 那么我们如何知道函数调用结束了呢?如果有连接到达了,我们的程序怎么知道呢?windows是怎样通知我们的程序的呢?所有麻烦都落到了我们程序员头上。最简单的方法循环执行Accept,检查是否有连接到达,这样我们的线程也不会被挂起。还可以通过线程同步来做,最常用的通过事件。
那么如何设置socket的堵塞和非堵塞模式呢?答案是调用ioctlsocket
//设置非堵塞模式
int setNonblock( int fd )
{
unsigned long nonblocking = 1;
ioctlsocket( fd, FIONBIO, (unsigned long*) &nonblocking );
return 0;
}
//设置堵塞模式
int setBlock( int fd )
{
unsigned long nonblocking = 0;
ioctlsocket( fd, FIONBIO, (unsigned long*) &nonblocking );
return 0;
}
int setNonblock( int fd )
{
unsigned long nonblocking = 1;
ioctlsocket( fd, FIONBIO, (unsigned long*) &nonblocking );
return 0;
}
//设置堵塞模式
int setBlock( int fd )
{
unsigned long nonblocking = 0;
ioctlsocket( fd, FIONBIO, (unsigned long*) &nonblocking );
return 0;
}
当然实际情况没有这么简单,例如如果调用了WSAAsyncSelect or WSAEventSelect 函数后,将不能再将socket对象设为堵塞模式,程序将会得到WSAEINVAL错误
后面的教程我们将分别探讨这两种模式。
有兴趣的可以看一下《精通Windows Sockets网络开发--基于C++实现》这本书,我没看过,不过听说不错,只可惜没有电子版,我只是得到了书中的例子代码。但对一些概念不是很清楚,于是翻阅msdn(英文的,真受不了),加上自己的理解,就有了这系列文章。以梳理所学,以回馈园友。