面试题答案
一键面试在非阻塞Socket编程中,可使用select
模块来实现简单的超时处理机制。以下是关键代码示例及原理解释:
- 关键代码示例
import socket
import select
# 创建非阻塞socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(False)
try:
sock.connect(('example.com', 80))
except BlockingIOError:
pass
# 设置超时时间,单位为秒
timeout = 5
readable, writable, exceptional = select.select([], [sock], [], timeout)
if sock in writable:
print('连接成功')
sock.sendall(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
readable, _, _ = select.select([sock], [], [], timeout)
if sock in readable:
data = sock.recv(1024)
print('收到数据:', data.decode('utf-8'))
else:
print('连接超时')
sock.close()
- 原理解释
select
函数:select
模块提供了select
函数,它允许程序监控多个文件描述符(在这个例子中是Socket对象),等待其中一个或多个变为可读、可写或发生异常。- 参数:
- 第一个参数是一个可读文件描述符的列表,这里为空
[]
,因为我们先关注连接是否成功(可写状态)。 - 第二个参数是一个可写文件描述符的列表,这里放入我们要连接的Socket对象
sock
。 - 第三个参数是一个异常文件描述符的列表,这里为空
[]
。 - 第四个参数
timeout
是超时时间,单位为秒。如果在这个时间内没有文件描述符变为指定状态,select
函数将返回空的列表。
- 第一个参数是一个可读文件描述符的列表,这里为空
- 连接超时处理:在尝试连接后,使用
select
函数等待Socket变为可写状态(意味着连接成功),如果在timeout
时间内Socket变为可写,则连接成功;否则,select
返回空列表,判定为连接超时。 - 数据接收超时处理:连接成功后,向服务器发送数据,然后再次使用
select
函数等待Socket变为可读状态(意味着有数据可接收),同样设置timeout
超时时间。如果在超时时间内Socket变为可读,则接收数据;否则,判定为数据接收超时。