阻塞和非阻塞套接字输入/输出
原文:https://www.studytonight.com/network-programming-in-python/blocking-and-nonblocking-socket-io
在客户端服务器应用中,当客户端向服务器发出请求时,服务器会处理该请求并发回响应。为此,客户端和服务器首先需要通过套接字(TCP 或 UDP)建立相互连接。在最后几个教程中,我们也看到了,客户端如何以请求的形式向服务器发送数据,服务器又如何对其进行操作,然后将响应发送回客户端。
阻塞套接字输入/输出
默认情况下,TCP 套接字处于阻塞模式。这意味着在某些特定操作完成之前,控件不会返回到程序中。
例如,如果您调用connect()
方法,连接会阻塞您的程序,直到操作完成。在许多情况下,我们不想让我们的程序永远等待。
再举一个例子,当我们编写一个连接到 web 服务器的 web 浏览器客户端时,我们应该考虑一个停止功能,它可以在其操作的中途取消一个活动的连接过程。这可以通过将插座置于非阻塞模式来实现。
无阻塞插座输入输出
我们可以调用setblocking(1)
设置阻塞或setblocking(0)
取消阻塞。让我们借助一个例子来理解它。首先,我们来考虑一个阻塞插座:
block_client.py
#!usr/bin/python
import socket
sock = socket.socket()
host = socket.gethostname()
sock.connect((host, 12345))
sock.setblocking(1)
# Or simply omit this line as by default TCP sockets
# are in blocking mode
data = "Hello Python\n" *10*1024*1024 # Huge amount of data to be sent
assert sock.send(data) # Send data till true
block_server.py
#!usr/bin/python
#block_server.py
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
s.bind((host,port))
s.listen(5)
while True:
conn, addr = s.accept() # accept the connection
data = conn.recv(1024)
while data: # till data is coming
print data
data = conn.recv(1024)
print "All Data Received" # Will execute when all data is received
conn.close()
break
现在,先运行block_server.py
,然后运行block_client.py
。你会注意到服务器一直在打印你好 Python 。这将一直持续下去,直到所有的数据都发送出去。在上面的代码中所有收到的数据这一行不会被打印很长时间,因为客户端需要发送大量的字符串,这需要时间,在此之前套接字输入输出会被阻塞。
这是怎么回事?send()
方法会尝试将所有数据传输到服务器,而写缓冲区会被填满。内核将使进程休眠,直到缓冲区中的数据被传输到目的地,并且缓冲区再次为空。当缓冲区变空时,内核将再次唤醒进程,以获取要传输的下一个数据块。简而言之,您的代码将会阻塞,并且不会让其他任何事情继续进行。
现在考虑一个无阻塞插座
#!usr/bin/python
# non_blocking_client.py
import socket
sock = socket.socket()
host = socket.gethostname()
sock.connect((host, 12345))
sock.setblocking(0) # Now setting to non-blocking mode
data = "Hello Python\n" *10*1024*1024 # Huge amount of data to be sent
assert sock.send(data) # Send data till true
现在,如果我们运行non_blocking_client.py
,你会注意到程序会运行一小段时间,它会打印最后一行“收到的所有数据”并很快终止。
这是怎么回事?这里客户端没有发送所有数据。当我们通过调用setblocking(0)
使一个套接字不阻塞时,它永远不会等待操作完成。所以当我们调用send()
方法时,它会将尽可能多的数据放入缓冲区并返回。