02select监听服务端
# can_read, can_write, _ = select.select(inputs, outputs, None, None)## 第一个参数是我们需要监听可读的套接字, 第二个参数是我们需要监听可写的套接字, 第三个参数使我们需要监听异常的套接字, 第四个则是时间限制设置.## 如果监听的套接字满足了可读可写条件, 那么所返回的can,read 或是 can_write就会有值了, 然后我们就可以利用这些返回值进行随后的操作了。相比较unix 的select模型, 其select函数的返回值是一个整型, 用以判断是否执行成功.## 第一个参数就是服务器端的socket, 第二个是我们在运行过程中存储的客户端的socket, 第三个存储错误信息。# 重点是在返回值, 第一个返回的是可读的list, 第二个存储的是可写的list, 第三个存储的是错误信息的# list。import select, socket, queuefrom time import sleep # 创造一个 TCP/IP连接server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 设置socket为异步模式。server.setblocking(False) # 绑定IP地址和端口# 创建一个IP,端口,本地IPserver_address = ('localhost', 8090)print('starting up on %s port %s' % server_address)# 绑定IP和端口server.bind(server_address) # 设置服务端监听数量server.listen(3)inputs = [server]# 处理要发送的数据outputs = [] # 输出的消息队列message_queues = {} while inputs: # 等待至少一个连接开始调用线程 print("waiting for the next event") # 开始select监听,对input_list中的服务器端的server开始进行监听 # 一旦调用socket的send,recv函数,将会再次调用此模块 # 这里监控三个参数,第一个返回的是可读的list, 第二个存储的是可写的list, 第三个存储的是错误信息的 readable, writable, exceptional = select.select(inputs, outputs, inputs) # 处理输入 # 循环判断是否有客户端连接进来,当有客户端连接进来的时候select将进行触发 for s in readable: # 判断当前触发的是不是服务端对象,当触发的是服务端对象, 说明有新的客户端连接进来了 if s is server: # 和客户端建立连接 connection, client_address = s.accept() # 打印客户端的链接 print('connection from', client_address) # 设置socket为异步模式。 connection.setblocking(0) # 将客户端对象也加入到监听列表中,当客户端发送消息的时候select也会触发。 inputs.append(connection) # 为连接的客户端单独建立一个消息队列,用来保存客户端发送的消息 message_queues[connection] = queue.Queue() else: # 有老用户发送消息,处理接收 # 由于客户端连接进来的时候服务端接收客户端的请求,将客户端也加入到了监听列表。 # 客户端发送的消息将触发。 # 判断触发对象是否为客户端 # 接收客户端的信息 data = s.recv(1024) # 客户端没有断开 if data != '': # 一个可用的客户端发送了数据 print('received "%s" from %s' % (data, s.getpeername())) # 将接受到的消息放到对应的客户端的消息队列中 message_queues[s].put(data) # 将需要进行回复操作的socket放到output列表中,让select监听 # 这里我们如果收到消息将服务端添加进入输出列表。 # 然后select就会监听到, if s not in outputs: outputs.append(s) else: # 客户端被监听到有变化,不是有客户端传过来的消息,就是客户端断开了。 # 客户端断开了连接,将客户端的监听从input列表中移除 print('closing', client_address) if s in outputs: outputs.remove(s) inputs.remove(s) s.close() # 移除对应的socket客户端对象的消息队列 del message_queues[s] # 处理输出。 # 如果现在没有客户端的请求,也没有客户端发送消息时,开始对发送的消息列表进行处理。 # 判断是否需要发送消息。 # 存储哪个客户端发送了消息。 for s in writable: try: # 如果消息队列中有消息,就从消息队列中获取要发送的消息。 message_queue = message_queues.get(s) sent_data = '' if message_queues is not None: # 如果队列为空的话不等(阻塞) send_data = message_queue.get_nowait() else: # 客户端断开连接了 print('has closed') # 如果队列为空的话,就代表着发送的消息完了,就需要从队列中删除。 except queue.Empty: print('%s' % (s.getpeername())) outputs.remove(s) else: # print "sending %s to %s " % (send_data, s.getpeername) # print "send something" if message_queue is not None: s.send(send_data) else: print("has closed ") # del message_queues[s] # writable.remove(s) # print "Client %s disconnected" % (client_address) # # Handle "exceptional conditions" # 处理异常的情况 # 如果有异常情况,那么就从输出队列中删除,然后关闭连接。 for s in exceptional: print('exception condition on', s.getpeername()) # Stop listening for input on the connection inputs.remove(s) if s in outputs: outputs.remove(s) s.close() # Remove message queue del message_queues[s] sleep(1)
赞 (0)