gra*_*tii 8 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()
Run Code Online (Sandbox Code Playgroud)
我似乎不理解的部分如下:
在代码片段中inputready,outputready,exceptready = select.select(input,[],[]),我相信该select()函数返回三个可能为输入,输出和异常条件的可等对象的空列表.因此,select()函数的第一个参数是包含服务器套接字和stdin的列表是有道理的.但是,我遇到困惑的地方就是else代码块.
由于我们用于循环输入套接字列表,很明显该select()函数将选择一个可以读取的客户端套接字.但是,在我们使用recv()并读取套接字实际已发送数据之后,我们希望将其回送给客户端.我的问题是我们如何写入这个套接字而不将其添加到作为select()函数调用的第二个参数传递的列表中?意思是,我们如何send()直接调用新套接字而不将其"注册" select()为可写套接字?
另外,为什么我们只在准备好读取的套接字上循环(在这种情况下是inputready)?是否有必要循环甚至输出已完成列表以查看哪些套接字已准备好写入?显然,我在这里遗漏了一些东西.
如果有人能够以更详细的方式解释select()功能的工作或指向良好的文档,那将是非常有用的.
谢谢.
这段代码可能只是一个简单的示例,因此并不详尽。即使 select 没有告诉您它们已准备好,您也可以在每个套接字中自由写入和读取。但是,当然,如果您这样做,您无法确定您的 send() 不会阻塞。所以,是的,最好的做法是依赖 select 进行写入操作。还有许多其他功能具有类似的目的,并且在许多情况下它们比 select 更好(例如epoll),但它们并非在所有平台上都可用。有关 select、epoll 和其他函数的信息可以在 Linux 手册页中找到。
然而,在 python 中,有许多不错的库用于处理许多连接,其中一些是:Twisted和gevent