windows下的6种IO模型

2021-02-13 14:15

阅读:472

阻塞模型

int recv(
SOCKET s,
char* buf,
int len,
int flags
);
int send(
SOCKET s,
const char* buf,
int len,
int flags
);

这种方式最为大家熟悉,Socket默认的就是阻塞模式。

在recv的时候,Socket会阻塞在那里,直到连接上有数据可读,把数据读到buffer里后recv函数才会返回,不然就会一直阻塞在那里。

如果在主线程中被阻塞,而数据迟迟没有过来,那么程序就会被锁死。这样的问题可以用多线程解决,但是在有多个套接字连接的情况下,这不是一个好的选择,扩展性很差,而且也容易有锁的问题。线程过多,也导致上下文切换过于频繁,导致系统变慢,而且大部分线程是处于非活动状态的话,这就大大浪费了系统的资源。

设置为非阻塞:

int ioctlsocket(
IN SOCKET s,
IN long cmd,
IN OUT u_long FAR * argp
);
#define FIONBIO /* set/clear non-blocking i/o */

调用ioctlsocket函数设置FIONBIO为1就转为非阻塞模式。

当recv和send函数没有准备好数据时,函数不会阻塞,立即返回错误值,用GetLastError返回的错误码为WSAEWOULDBLOCK,中文解释为“无法立即完成一个非阻挡性套接字的操作”。

当然,这里你可以用非阻塞模拟阻塞模式,就是用while循环不停调用recv,直到recv返回成功为止。这样的效率也不高,但好处在于你能在没接收到数据时,有空进行其他操作,或者直接Sleep。

把套接字设置为非阻塞模式,即告诉系统:在调用Windows socket API时,不让主调线程睡眠,而让函数立即返回。比如在调用recv函数时,即使此时接受缓冲区没有数据,也不会导致线程在recv处等待,recv函数会立即返回。如果没有调用成功函数会返回WSAEROULDBLOCK错误代码。为了接收到数据必须循环调用recv,这也是非阻塞与阻塞模式的主要区别。

 

unsigned long ul=1;  
  
int ret;  
  
s=socket(AF_INET,SOCK_STREAM,0);  
  
ret=ioctlsocket(s,FIONBIO,(unsigned long *)&ul);//设置成非阻塞模式。  
  
if(ret==SOCKET_ERROR)//设置失败。  
  
{  
  
}  

 

  

 


评论


亲,登录后才可以留言!