The duration of this section needs to be controlled 15 Within minutes
Linux Next , Can be set by socket Turn it into non-blocking. When it comes to one non-blocking socket When reading , The process is like this :
As you can see from the diagram , When the user process issues read In operation , If kernel The data in is not ready , Then it won't block User process , But immediately return to a error. From the perspective of user process , It launched a read After the operation , There is no need to wait , It's about getting an immediate result . The result of user process judgment is a error when , It knows the data is not ready , So the user can launch this time to the next time read Do other things in the interval of inquiry , Or send it again read operation . once kernel The data in is ready , And again received the user process's system call, Then it immediately copies the data to the user memory ( This stage is still blocked ), Then return .
That is to say, non blocking recvform After the system call , The process is not blocked , The kernel immediately returns to the process , If the data is not ready ,
This will return to a error. After the process returns , You can do something else , And then launch recvform system call . Repeat the process above ,
Go back and forth recvform system call . This process is often called polling . Polling for kernel data , Until the data is ready , Then copy the data to the process ,
Data processing . We need to pay attention to , The whole process of copying data , The process is still in a blocked state .
therefore , In non blocking IO in , In fact, the user process needs continuous active inquiry kernel Is the data ready .
Non blocking IO Example
# Server side
from socket import *
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8099))
server.listen(5)
server.setblocking(False)
rlist=[]
wlist=[]
while True:
try:
conn, addr = server.accept()
rlist.append(conn)
print(rlist)
except BlockingIOError:
del_rlist=[]
for sock in rlist:
try:
data=sock.recv(1024)
if not data:
del_rlist.append(sock)
wlist.append((sock,data.upper()))
except BlockingIOError:
continue
except Exception:
sock.close()
del_rlist.append(sock)
del_wlist=[]
for item in wlist:
try:
sock = item[0]
data = item[1]
sock.send(data)
del_wlist.append(item)
except BlockingIOError:
pass
for item in del_wlist:
wlist.remove(item)
for sock in del_rlist:
rlist.remove(sock)
server.close()
# client
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8080))
while True:
msg=input('>>: ')
if not msg:continue
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data.decode('utf-8'))
But non blocking IO Models are never recommended .
We can't do otherwise : Be able to do other work while waiting for the task to be completed ( Including submitting other tasks , That is to say “ backstage ” There can be multiple tasks in “” meanwhile “” perform ).
But it's hard to hide its shortcomings :
1\. Cycle call recv() Will push up by a large margin CPU Occupancy rate ; This is what we left in the code time.sleep(2) Why , Otherwise, it is easy to get stuck under the low configuration host
2\. The response delay for task completion increases , Because it takes a while to poll read operation , The task may be completed at any time between polls .
This leads to a reduction in overall data throughput .
Besides , In this scheme recv() It's more about detection “ Is the operation complete ” The role of , The actual operating system provides more efficient detection “ Is the operation complete “ Interface of action , for example select() Multiplexing mode , It can detect whether multiple connections are active at one time .