select原理还不太明白,但是select的作用可以理解为监听
将监听对象列表传入,当其中的某个对象处于活跃状态,返回该对象
select监听一般用于IO阻塞,在活动室时才进行操作,减少阻塞
import queue
import select
import socket
host = 'localhost'
port = 10086
address = host, port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address)
server.listen()
inputs = [server]
outputs = []
message = {}
while True:
read, write, error = select.select(inputs, outputs, inputs)
for r in read:
if r is server:
conn = r.accept()[0]
inputs.append(conn)
message[conn] = queue.Queue()
else:
message[r].put(r.recv(1024))
outputs.append(r)
for w in write:
w.sendall(message[w].get())
outputs.remove(w)
for e in error:
inputs.remove(e) or e in outputs and outputs.remove(e)
监听的对象分为三类:
readable:可读对象,也就是IO中的输入,也就是连接
writeable:可写对象,就是发送
exceptional:异常
指定监听的语法为:
read, write, error = select.select(inputs, outputs, inputs)
括号中传入需要监听的对象,返回的是监听到的活跃对象
当没有活跃对象时,会自动阻塞
可以理解为进行下一步操作的必要前置条件,不满足就阻塞,直到满足条件才能执行下一步操作
相较于原来的IO阻塞,这种监听方式把阻塞行为交给程序员来进行控制,更容易理解和控制
操作部分:
1. 连接:
监听对象,明白当前局势,制定后续操作
2. 执行:
根据计划施行
3. 防范:
异常情况修正监听对象和计划施行
上述代码执行步骤:
1. 连接:
监听服务端状况,添加客户端连接,并为客户端准备数据存储
监听客户端连接,存储客户端发送数据
2. 执行:
根据客户端输入,对输入数据进行处理,对每一个客户端进行回应
3. 防范:
对于出现异常的连接,从监听中去除
对应客户端代码:
import socket
host = 'localhost'
port = 10086
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
address = host, port
client.connect(address)
while True:
data = input('>>')
client.send(bytes(data, encoding='utf-8'))
get = str(client.recv(1024), encoding='utf-8')
print('<<{}'.format(get))
为了凸显逻辑,代码中异常未处理
服务端:接收数据处,未接收到数据应该将连接移除监听队列,并关闭
客户端:接收处应该捕捉异常,并进行关闭