如果在超时发生之前没有收到数据,Python 的 socket.recv() 为非阻塞套接字返回什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16745409/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs?
提问by El Ninja Trepador
Basically, I've read in several places that socket.recv()will return whatever it can read, or an empty string signalling that the other side has shut down (the official docs don't even mention what it returns when the connection is shut down... great!). This is all fine and dandy for blocking sockets, since we know that recv()only returns when there actually is something to receive, so when it returns an empty string, it MUSTmean the other side has closed the connection, right?
基本上,我在几个地方读过,它们socket.recv()会返回它可以读取的任何内容,或者是一个空字符串,表明对方已经关闭(官方文档甚至没有提到连接关闭时它返回的内容......伟大的!)。这对于阻塞套接字来说很好,很花哨,因为我们知道recv()只有在真正有东西要接收时才返回,所以当它返回一个空字符串时,它一定意味着另一方已经关闭了连接,对吧?
Okay, fine, but what happens when my socket is non-blocking?? I have searched a bit (maybe not enough, who knows?) and can't figure out how to tell when the other side has closed the connection using a non-blocking socket. There seems to be no method or attribute that tells us this, and comparing the return value of recv()to the empty string seems absolutely useless... is it just me having this problem?
好的,很好,但是当我的套接字非阻塞时会发生什么?我已经搜索了一点(也许还不够,谁知道?)并且无法弄清楚如何判断另一方何时使用非阻塞套接字关闭了连接。似乎没有方法或属性可以告诉我们这一点,并且将 的返回值recv()与空字符串进行比较似乎绝对没用……难道只有我有这个问题吗?
As a simple example, let's say my socket's timeout is set to 1.2342342 (whatever non-negative number you like here) seconds and I call socket.recv(1024), but the other side doesn't send anything during that 1.2342342 second period. The recv()call will return an empty string and I have no clue as to whether the connection is still standing or not...
举一个简单的例子,假设我的套接字超时设置为 1.2342342(你喜欢这里的任何非负数)秒,我调用socket.recv(1024),但另一端在 1.2342342 秒期间不发送任何内容。该recv()调用将返回一个空字符串,我不知道连接是否仍然存在...
采纳答案by mshildt
In the case of a non blocking socket that has no data available, recv will throw the socket.error exception and the value of the exception will have the errno of either EAGAIN or EWOULDBLOCK. Example:
在没有可用数据的非阻塞套接字的情况下,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:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)
The situation is a little different in the case where you've enabled non-blocking behavior via a time out with socket.settimeout(n)or socket.setblocking(False). In this case a socket.error is stil raised, but in the case of a time out, the accompanying value of the exception is always a string set to 'timed out'. So, to handle this case you can do:
在您通过超时启用非阻塞行为的情况下,情况略有不同socket.settimeout(n)或socket.setblocking(False)。在这种情况下,仍然会引发 socket.error,但在超时的情况下,异常的伴随值始终是设置为“超时”的字符串。因此,要处理这种情况,您可以执行以下操作:
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 :)
As indicated in the comments, this is also a more portable solution since it doesn't depend on OS specific functionality to put the socket into non-blockng mode.
正如评论中所指出的,这也是一个更便携的解决方案,因为它不依赖于操作系统特定的功能来将套接字置于非阻塞模式。
See recv(2)and python socketfor more details.
有关更多详细信息,请参阅recv(2)和python 套接字。
回答by Bar?? U?akl?
When you use recvin connection with selectif the socket is ready to be read from but there is no data to read that means the client has closed the connection.
当您使用recv连接时,select如果套接字已准备好读取但没有数据可读取,则表示客户端已关闭连接。
Here is some code that handles this, also note the exception that is thrown when recvis called a second time in the while loop. If there is nothing left to read this exception will be thrown it doesn't mean the client has closed the connection :
这是一些处理此问题的代码,还要注意recv在 while 循环中第二次调用时抛出的异常。如果没有任何东西可供阅读,将抛出此异常,这并不意味着客户端已关闭连接:
def listenToSockets(self):
while True:
changed_sockets = self.currentSockets
ready_to_read, ready_to_write, in_error = select.select(changed_sockets, [], [], 0.1)
for s in ready_to_read:
if s == self.serverSocket:
self.acceptNewConnection(s)
else:
self.readDataFromSocket(s)
And the function that receives the data :
以及接收数据的函数:
def readDataFromSocket(self, socket):
data = ''
buffer = ''
try:
while True:
data = socket.recv(4096)
if not data:
break
buffer += data
except error, (errorCode,message):
# error 10035 is no data available, it is non-fatal
if errorCode != 10035:
print 'socket.error - ('+str(errorCode)+') ' + message
if data:
print 'received '+ buffer
else:
print 'disconnected'
回答by jfs
It is simple: if recv()returns 0 bytes; you will not receive any more data on this connection. Ever.You still might be able to send.
很简单:ifrecv()返回 0 字节;您将不会再收到有关此连接的任何数据。曾经。您仍然可以发送。
It means that your non-blocking socket have to raise an exception (it might be system-dependent) if no data is available but the connection is still alive (the other end may send).
这意味着如果没有数据可用但连接仍然存在(另一端可能发送),则您的非阻塞套接字必须引发异常(它可能取决于系统)。
回答by Ulrich Eckhardt
Just to complete the existing answers, I'd suggest using select instead of nonblocking sockets. The point is that nonblocking sockets complicate stuff (except perhaps sending), so I'd say there is no reason to use them at all. If you regularly have the problem that your app is blocked waiting for IO, I would also consider doing the IO in a separate thread in the background.
为了完成现有的答案,我建议使用 select 而不是 nonblocking sockets。关键是非阻塞套接字使事情复杂化(除了可能发送),所以我想说根本没有理由使用它们。如果您经常遇到应用程序阻塞等待 IO 的问题,我也会考虑在后台的单独线程中执行 IO。

