python - Python的select模块中的select()函数究竟是如何工作的呢?

标签 python sockets select network-programming

我正在使用 Python 编写一个面向网络的应用程序。我之前曾致力于使用阻塞套接字,但在更好地了解需求和概念之后,我想使用非阻塞套接字编写应用程序,从而编写一个事件驱动的服务器。

我理解Python中select模块中的函数就是为了方便的查看我们对哪个socket感兴趣等等。为此,我基本上是在尝试浏览几个事件驱动服务器的示例,而我遇到了这个:

"""
An echo server that uses select to handle multiple clients at a time.
Entering any line of input at the terminal will exit the server.
"""

import select
import socket
import sys

host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,sys.stdin]
running = 1
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

    for s in inputready:

        if s == server:
            # handle the server socket
            client, address = server.accept()
            input.append(client)

        elif s == sys.stdin:
            # handle standard input
            junk = sys.stdin.readline()
            running = 0

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)
server.close() 

我似乎没看懂的部分如下:

在代码片段 inputready,outputready,exceptready = select.select(input,[],[]) 中,我相信 select() 函数可能返回三个输入、输出和异常条件的可等待对象的空列表。因此 select() 函数的第一个参数是包含服务器套接字和标准输入的列表是有道理的。但是,我感到困惑的地方是代码的 else block 。

由于我们在 inputready 套接字列表上进行 for 循环,很明显 select() 函数将选择一个准备好被读取的客户端套接字。然而,当我们使用recv() 读取数据并发现套接字确实发送了数据后,我们会想将其回显给客户端。我的问题是,我们如何才能写入此套接字而不将其添加到作为 select() 函数调用的第二个参数传递的列表中?意思是,我们如何才能直接在新套接字上调用 send() 而无需使用 select() 将其“注册”为可写套接字?

此外,为什么我们只在准备好读取的套接字上循环(在本例中为输入就绪)?难道不需要遍历 outputready 列表来查看哪些套接字已准备好写入? 显然,我在这里遗漏了一些东西。

如果有人能以更详细的方式解释 select() 函数的工作原理或指出好的文档,那也会非常有帮助。

谢谢。

最佳答案

可能该代码片段只是一个简单的示例,因此并不详尽。您可以在每个套接字中自由写入和读取,即使 select 没有告诉您它们已准备就绪。但是,当然,如果你这样做,你不能确定你的 send() 不会阻塞。 所以,是的,最好的做法是也依赖 select 来进行写操作。 还有许多其他功能具有类似的目的,在许多情况下它们比 select 更好(例如 epoll ),但它们并非在所有平台上都可用。 有关 select、epoll 和其他函数的信息可以在 Linux 手册页中找到。

然而在 python 中有许多用于处理许多连接的不错的库,其中一些是:Twistedgevent

关于python - Python的select模块中的select()函数究竟是如何工作的呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20471816/

相关文章:

c++ - 编写第一个监听 C++ 应用程序

MySQL select 语句删除 WHERE 子句中的空格

linux - 其他进程关闭fifo时无法从epoll_wait中唤醒

python - 使用 Python 在 Parquet 中嵌套数据

python - 将 odoo 图像存储到文件系统中

python - 测试类的 PEP8 命名约定

c++ - 如何正确读取套接字消息 (C++)

linux - socat 监听分配给特定网络接口(interface)的所有 IP

SQL 查询在 SQL Server 中获取逗号分隔符中的聚合结果以及按列分组

python - 如何计算 JSON 数据中的项目