我正在用Python编写面向网络的应用程序。我之前从事过使用阻塞套接字的工作,但是在对需求和概念有了更好的了解之后,我想使用非阻塞套接字(因此是事件驱动的服务器)编写应用程序。

我知道Python中的select模块中的函数将用于方便地查看哪个套接字使我们感兴趣,依此类推。为此,我基本上是试图翻阅事件驱动服务器的几个示例,而我遇到了这个示例:

"""
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()函数的第一个参数是包含服务器套接字和stdin的列表。但是,我遇到困惑的地方是代码的else块。

由于我们在循环输入准备好的套接字列表,因此很明显select()函数将选择准备读取的客户机套接字。但是,在我们使用recv()读取数据并发现套接字实际上已经发送了数据之后,我们希望将其回显给客户端。我的问题是,如何在不将其添加到作为select()函数调用的第二个参数传递的列表的情况下写入此套接字?意思是,我们如何直接在新套接字上调用send()而不将select()作为可写套接字“注册”呢?

另外,为什么我们只在准备读取的套接字上循环(在这种情况下为inputready)?是否有必要甚至遍历outputready列表以查看准备好写入哪些套接字?
显然,我在这里错过了一些东西。

如果有人可以更详细地解释select()函数的工作或指向好的文档,那也将非常有帮助。

谢谢你。

最佳答案

这段代码可能只是一个简单的示例,因此并不详尽。您可以自由地在每个套接字中进行读写,如果select不能告诉您它们已经准备好了。但是,当然,如果执行此操作,则不能确保send()不会阻塞。
因此,是的,最好也依赖于select来进行写操作。
还有许多其他功能具有相似的目的,在许多情况下,它们要比选择功能更好(例如epoll),但并非在所有平台上都可用。
有关select,epoll和其他功能的信息可以在Linux手册页中找到。

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

10-07 19:16
查看更多