阻塞和非阻塞套接字输入/输出

原文: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()方法时,它会将尽可能多的数据放入缓冲区并返回。