如果在超时发生之前没有收到数据,Python的socket.recv()返回非阻塞套接字是什么?

基本上,我在几个地方读过socket.recv()将返回它可以读取的任何东西,或一个空字符串表示另一方已关闭(官方文档甚至没有提及它返回什么时,连接是关闭…太棒了!)。这是所有罚款和dandy阻塞套接字,因为我们知道recv()只返回时,实际上有东西要接收,所以当它返回一个空字符串,它必须意味着另一方已经关闭连接,对吗?

好吧,好,但是当我的套接字是非阻塞的时候会发生什么?我已经搜索了一点(也许不够,谁知道?),并不能弄清楚如何告诉何时另一方使用非阻塞套接字关闭连接。似乎没有方法或属性告诉我们这个,并将recv()的返回值和空字符串比较似乎绝对没用…只是我有这个问题吗?

作为一个简单的例子,假设我的套接字的超时设置为1.2342342(无论你喜欢这里的非负数)秒,我调用socket.recv(1024),但另一方在1.2342342秒期间不发送任何东西。 recv()调用将返回一个空字符串,我不知道连接是否仍然处于静止状态…

在没有数据可用的非阻塞套接字的情况下,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 :)

在通过socket.settimeout(n)socket.setblocking(False)超时启用非阻塞行为的情况下,情况略有不同。在这种情况下,会出现一个套接字错误,但是在超时的情况下,附带的值的异常总是一个字符串设置为“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]
        # 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 :)

如注释中所示,这也是一种更可移植的解决方案,因为它不依赖于操作系统特定的功能将套接字置于非阻塞模式。

有关详细信息,请参阅recv(2)python socket

http://stackoverflow.com/questions/16745409/what-does-pythons-socket-recv-return-for-non-blocking-sockets-if-no-data-is-r

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:如果在超时发生之前没有收到数据,Python的socket.recv()返回非阻塞套接字是什么?