当我们建立了一个连接,可以不用等网页服务器的数据返回就可以接着做其它事情,当网页服务器准备好数据了,便会通知程序:数据准备好了,快来调用我吧。
下面我们来编写一个客户端服务器模型来理解以下阻塞以及非阻塞
server.py
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 5000))
sock.listen(1)
while True:
sc, sockname = sock.accept()
print('I have accepted a connection from', sockname)
print('Socket name: ', sc.getsockname())
print('Socket peer: ', sc.getpeername())
message = sc.recv(64)
print('Recevied info is ', repr(message))
time.sleep(3)//返回数据之前,先暂停3s
sc.sendall(b'Response from server')
sc.close()
block-client.py
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 5000))
sock.send(b'Resquest from client')
response = sock.recv(64)
sock.close()
print(response)
print('Test for blocking')//阻塞模式下,这条信息会在3s后才能输出
运行结果如下:
阻塞模式
from selectors import *
import socket
def connected(key, mask):
selector.unregister(key.fd)
sock.send(b'Resquest from client')
selector.register(key.fd, EVENT_READ, read_response) #注册为一个读的event
print('Test for non blocking')
def read_response(key, mask):
global stopped
response = sock.recv(64)
print(response)
selector.unregister(key.fd)
stopped = True
selector = DefaultSelector()
stopped = False
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #注册为一个写的event
sock.setblocking(False)
try:
sock.connect(('localhost', 5000))
except:
pass
selector.register(sock.fileno(), EVENT_WRITE, connected)
while not stopped:
events = selector.select()#选取已经准备好的event
for event_key, event_mask in events:
callback = event_key.data
callback(event_key, event_mask) #回调函数
运行结果
在非阻塞模式中,把读和写注册为
event
,在它们未准备好之前,我们先可以执行其它的程序,在它们准备好之后,利用回调函数来进行程序的执行。对于上面的程序我们可以这样来解释,当我们要在
socket
中写入数据时,把它注册为一个event
,当写入的操作准备好时再写入,在写入操作未准备好时,我们可以执行其它的程序我们可以把写入的操作定义为一个回调函数,当系统提醒我们说:文件准备好了,可以开始写了。我们就会调用回调函数
connected
在写入操作完成后,我们就需要进行读取操作了,这时精彩的地方来了,程序会先输出Test for non blocking
为什么呢?
因为读取操作还没准备好,注意我们在server.py
中写入了time.sleep(3)
,因此三秒之内读取操作是不会准备好的,这时就会执行其它程序,因此会先输出Test for non blocking
PS:
如果有什么错误或者疑问,可以在评论区指出