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

2025-03-14 08:57:00
admin
原创
81
摘要:问题描述:基本上,我在几个地方读到过它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大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3975  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2742  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   80  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   88  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   77  
热门文章
项目管理软件有哪些?
曾咪二维码

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

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

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用