对于没有可用数据的非阻塞套接字,recv会抛出socket.error异常,并且异常的值将具有EAGAIN或EWOULDBLOCK的errno。例如:
import sys
import socket
import fcntl, os
import errno
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
try:
msg = s.recv(4096)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
else:
print e
sys.exit(1)
else:
如果你通过socket.settimeout(n)
或socket.setblocking(False)
启用了非阻塞行为的超时,情况就有些不同了。在这种情况下,仍然会引发一个socket.error异常,但是在超时的情况下,异常的附带值始终设置为“timed out”的字符串。因此,要处理此情况,可以执行以下操作:
import sys
import socket
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.settimeout(2)
while True:
try:
msg = s.recv(4096)
except socket.timeout, e:
err = e.args[0]
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
评论中提到,这也是一种更具可移植性的解决方案,因为它不依赖于操作系统特定的功能来将套接字置于非阻塞模式。
有关详细信息,请参见recv(2)和Python套接字。