我正在用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中,有许多不错的库用于处理许多连接,其中一些是:Twisted和gevent