如果在超时之前没有收到任何数据,那么 Python 的 socket.recv() 对于非阻塞套接字将返回什么?

2025-03-14 08:57:00
admin
原创
53
摘要:问题描述:基本上,我在几个地方读到过它socket.recv()会返回任何可以读取的内容,或者一个空字符串,表示另一端已关闭(官方文档甚至没有提到当连接关闭时它会返回什么……太棒了!)。这对于阻塞套接字来说都很好,因为我们知道recv()只有当实际有东西要接收时才会返回,所以当它返回一个空字符串时,它一定意味...

问题描述:

基本上,我在几个地方读到过它socket.recv()会返回任何可以读取的内容,或者一个空字符串,表示另一端已关闭(官方文档甚至没有提到当连接关闭时它会返回什么……太棒了!)。这对于阻塞套接字来说都很好,因为我们知道recv()只有当实际有东西要接收时才会返回,所以当它返回一个空字符串时,它一定意味着另一端已经关闭了连接,对吧?

好的,很好,但是当我的套接字是非阻塞的时会发生什么?我搜索了一下(可能还不够,谁知道呢?),但还是搞不清楚如何判断对方何时使用非阻塞套接字关闭了连接。似乎没有方法或属性可以告诉我们这一点,将返回值recv()与空字符串进行比较似乎完全没用……只有我有这个问题吗?

举一个简单的例子,假设我的套接字超时设置为 1.2342342(这里任意一个非负数)秒,然后我调用socket.recv(1024),但另一端在 1.2342342 秒内没有发送任何内容。调用recv()将返回一个空字符串,我不知道连接是否仍然有效...


解决方案 1:

对于非阻塞套接字,若没有可用数据,recv 将抛出 socket.error 异常,异常值的 errno 为 EAGAIN 或 EWOULDBLOCK。例如:

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,但在超时的情况下,异常的伴随值始终是设置为“超时”的字符串。因此,要处理这种情况,您可以执行以下操作:

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。

解决方案 2:

很简单:如果recv()返回 0 字节;您将不会再通过此连接接收任何数据。永远。您仍可以发送。

这意味着如果没有可用数据但连接仍然处于活动状态(另一端可能发送),则非阻塞套接字必须引发异常(它可能与系统有关)。

解决方案 3:

当您使用recv连接时select,如果套接字已准备好读取但没有可读取的数据,则意味着客户端已关闭连接。

下面是处理此问题的一些代码,还请注意在 while 循环中第二次调用时抛出的异常recv。如果没有剩余内容可读,则会抛出此异常,但这并不意味着客户端已关闭连接:

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)

接收数据的函数:

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'

解决方案 4:

为了完成现有的答案,我建议使用 select 而不是非阻塞套接字。关键是非阻塞套接字使事情变得复杂(也许除了发送),所以我认为根本没有理由使用它们。如果您经常遇到应用程序被阻塞等待 IO 的问题,我还会考虑在后台的单独线程中执行 IO。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用