我几乎总是以阻塞模式在套接字上接收数据,这很好用。但有时我不想等待——如果套接字上有数据,我现在就要获取它,否则稍后再试。
我认为可以使用
从Python socket文档中得知,flags参数具有与Unix recv相同的含义:
我理解为我可以在该调用中传递
一些示例代码:一个简单的阻塞调用。如预期的那样,大约需要0.5秒。
MSG_DONTWAIT:我希望是非阻塞调用,非常快地返回。实际上,这也需要约0.5秒。
通过重新配置端口进行非阻塞。实际上,这只需约50微秒,因此其阻塞方式与前两个调用不同。
我认为可以使用
socket.recv()
的flags参数来实现此操作,但似乎不起作用。我可以使用socket.setblocking()
和socket.settimeout()
函数来实现所需的效果,但这看起来很麻烦。从Python socket文档中得知,flags参数具有与Unix recv相同的含义:
MSG_DONTWAIT (since Linux 2.2)
Enables nonblocking operation; if the operation would block, the
call fails with the error EAGAIN or EWOULDBLOCK. This provides
similar behavior to setting the O_NONBLOCK flag (via the fcntl(2)
F_SETFL operation), but differs in that MSG_DONTWAIT is a per-call
option, whereas O_NONBLOCK is a setting on the open file description
(see open(2)), which will affect all threads in the calling process
and as well as other processes that hold file descriptors referring
to the same open file description.
我理解为我可以在该调用中传递
socket.MSG_DONTWAIT
以获取非阻塞操作。 可能这不正确-我也可以理解为它总是返回错误,因为该调用原则上将是阻塞的。如果是这样,那么这一切都不相关。一些示例代码:
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.settimeout(0.5)
starttime = time.time()
try:
m = sock.recv(100)
except socket.timeout as e:
pass
endtime = time.time()
print(f'sock.recv(100) took {endtime-starttime}s') # 0.5s
starttime = time.time()
try:
m = sock.recv(100, socket.MSG_DONTWAIT)
except socket.timeout as e:
pass
endtime = time.time()
print(f'sock.recv(100, socket.MSG_DONTWAIT) took {endtime-starttime}s') # 0.5s
starttime = time.time()
timeout = sock.gettimeout()
sock.setblocking(0)
try:
m = sock.recv(100)
except BlockingIOError as e:
pass
sock.settimeout(timeout)
endtime = time.time()
print(f'sock.recv(100) with non-blocking set took {endtime-starttime}s') # 4.96e-5s
问题:
- 我对使用MSG_DONTWAIT的方式是否正确有疑问,它应该能按照我尝试的方式工作吗?
- 是否有更好的方法来切换recv()的阻塞和非阻塞调用?