如果在超时发生之前没有收到数据,Python 的 socket.recv() 为非阻塞套接字返回什么? [英] What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs?

查看:40
本文介绍了如果在超时发生之前没有收到数据,Python 的 socket.recv() 为非阻塞套接字返回什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我在几个地方读到 socket.recv() 将返回它可以读取的任何内容,或者一个空字符串表示对方已经关闭(官方文档不甚至没有提到连接关闭时它返回的内容......太好了!).这对于阻塞套接字来说很好,很花哨,因为我们知道 recv() 只在确实有东西要接收时才返回,所以当它返回一个空字符串时,它必须 表示对方关闭了连接,对吧?

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 MUST mean the other side has closed the connection, right?

好吧,但是当我的套接字非阻塞时会发生什么??我已经搜索了一点(也许还不够,谁知道?)并且无法弄清楚如何判断另一方何时使用非阻塞套接字关闭了连接.似乎没有方法或属性可以告诉我们这一点,将 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?

举一个简单的例子,假设我的套接字超时设置为 1.2342342(你喜欢这里的任何非负数)秒,我调用 socket.recv(1024),但另一端没有在 1.2342342 秒期间不发送任何内容.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...

推荐答案

在没有可用数据的非阻塞socket的情况下,recv会抛出socket.error异常,异常值的errno为EAGAIN 或 EWOULDBLOCK.示例:

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:

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).在这种情况下,仍然会引发 socket.error,但在超时的情况下,异常的伴随值始终是设置为超时"的字符串.因此,要处理这种情况,您可以执行以下操作:

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:

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.

参见 recv(2)python 套接字了解更多详情.

See recv(2) and python socket for more details.

这篇关于如果在超时发生之前没有收到数据,Python 的 socket.recv() 为非阻塞套接字返回什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆