文章目录

  • 1. 阻塞模式
  • 四种阻塞API调用
  • 2. 非阻塞模式
  • 3. 优缺点对比


阻塞(blocking)、非阻塞(non-blocking):

Windows套接字在阻塞和非阻塞两种模式下执行I/O操作。在阻塞模式下,在I/O操作完成前,执行的操作函数一直等候而不会立即返回,该函数所在的线程会阻塞在这里。相反,在非阻塞模式下,套接字函数会立即返回,而不管I/O是否完成,该函数所在的线程会继续运行。

1. 阻塞模式

阻塞模式的套接字上,调用任何一个Windows Sockets API都会耗费等待时间。

比如当调用recv()函数时,系统首先查是否有准备好的数据。如果数据没有准备好,那么系统就处于等待状态。当数据准备好后,将数据从系统内核缓冲区复制到用户空间,然后该函数返回。在套接应用程序中,当调用recv()函数时,未必用户空间就已经存在数据,那么此时recv()函数就会处于等待状态。

windows python socket非阻塞 python socket阻塞和非阻塞_套接字

四种阻塞API调用

  • 输入操作

recv()recvfrom()函数。以阻塞套接字为参数调用该函数接收数据。如果此时套接字缓冲区内没有数据可读,则调用线程在数据到来前一直睡眠。

  • 输出操作

send()sendto()函数。以阻塞套接字为参数调用该函数发送数据。如果套接字缓冲区没有可用空间,线程会一直睡眠,直到有空间。

  • 接收函数

accept()函数。以阻塞套接字为参数调用该函数,等待接受对方的连接请求。如果此时没有连接请求,线程就会进入睡眠状态。

  • 外出连接

connect()。对于TCP连接,客户端以阻塞套接字为参数,调用该函数向服务器发起连接。该函数在收到服务器的应答前,不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。

注意:

并不是所有Windows SocketsAPI以阻塞套接字为参数调用都会发生阻塞。例如,以阻塞模式的套接字为参数调用bind()listen()函数时,函数会立即返回。

2. 非阻塞模式

windows python socket非阻塞 python socket阻塞和非阻塞_阻塞与非阻塞_02

把套接字设置为非阻塞模式,即通知系统内核:在调用SocketsAPI时,应让函数立即返回,并返回一个错误代码。

比如,一个非阻塞模式套接字多次调用recv()函数的过程。前三次调用recv()函数时,内核数据还没有准备好。因此,该函数立即返回WSAEWOULDBLOCK错误代码。第四次调用recv()函数时,数据已经准备好,被复制到应用程序的缓冲区中,recv()函数返回成功指示,应用程序开始处理数据。

当使用socket()函数和WSASocket()函数创建套接字时默认都是阻塞的。在创建套接字之后,windows下通过调用ioctlsocket()函数(Linux下fcntl),将该套接字设置为非阻塞模式。

套接字设置为非阻塞模式后,在调用Windows Sockets APl函数时,调用函数会立即返回。大多数情况下,这些函数调用都会调用“失败”,并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常,应用程序需要重复调用该函数,直到获得成功返回代码。但特例bind()函数不会返回该错误代码。

除了使用ioctlsocket()函数将套接字,设置为非阻塞模式之外,还可以使用WSAAsyncselect()WSAEventselect()函数,当调用该函数时,套接字会自动地设置为非阻塞方式。

由于使用非阻塞套接字在调用函数时,会经常返回WSAEWOULDBLOCK错误。所以在任何时候,都应仔细检查返回代码并作好对“失败”的准备。应用程序连续不断地调用这个函数,直到它返回成功指示为止。上面的程序清单中,在While循环体内不断地调用recv()函数,以读入1024个字节的数据。这种做法很浪费系统资源。

3. 优缺点对比

windows python socket非阻塞 python socket阻塞和非阻塞_socket_03