<p>对于没有可用数据的非阻塞套接字,recv将抛出socket.error异常,该异常的值将具有EAGAIN或ewooldblock的errno。示例:</p>
<pre><code>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:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)
</code></pre>
<p>当您通过使用<a href="https://docs.python.org/2.7/library/socket.html#socket.socket.settimeout" rel="noreferrer">^{<cd1>}</a>或<a href="https://docs.python.org/2.7/library/socket.html#socket.socket.setblocking" rel="noreferrer">^{<cd2>}</a>超时来启用非阻塞行为时,情况略有不同。在这种情况下,会引发socket.error,但在超时的情况下,伴随的异常值始终是设置为“超时”的字符串。所以,要处理这个案子,你可以:</p>
<pre><code>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]
# this next if/else is a bit redundant, but illustrates how the
# timeout exception is setup
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
# Something else happened, handle error, exit, etc.
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
# got a message do something :)
</code></pre>
<p>如注释所示,这也是一个更可移植的解决方案,因为它不依赖于操作系统特定的功能来将套接字置于非阻塞模式。</p>
<p>有关详细信息,请参见<a href="http://linux.die.net/man/2/recv" rel="noreferrer">recv(2)</a>和<a href="https://docs.python.org/2.7/library/socket.html" rel="noreferrer">python socket</a>。</p>