服务端的代码
import socketimport queueimport selectip_bind = ("127.0.0.1",9000)message_queue = {}#保存客户端发送过来的信息,将消息放入到队列中input_list = []output_list = []if __name__ == '__main__': server = socket.socket() server.bind(ip_bind) server.listen(10) server.setblocking(False) #设置socket服务端为非阻塞的 input_list.append(server) #初始化将服务端加入到监听列表中 while True: print("waiting for new connection") stdinput,stdoutput,stderr = select.select(input_list,output_list,input_list,2) #开始select监听,对input_list中的服务端server进行监听 for obj in stdinput: #判断是否有客户端连接进来,当有客户端连接进来时select将触发,就会进入循环 if obj == server: #代表一个新的连接进来 #判断当前触发的是不是服务端的对象,当触发的对象是服务端的对象时候,说明 #有新的客户端连接进来了 conn,addr = server.accept() print("Client {0} is connected".format(addr)) conn.setblocking(False) #把这个新连接的实例设置为非阻塞 #这个时候我们不能立即接受数据,因为在select中,是单线程的,如果这里直接开始接受数据,那么其他的客户端就无法连接进来了,所以只能 #先把这个链接存起来,放到一个input_list中,为什么放到input_list中呢,因为我们想监控这个链接,如果这个客户端有消息过来,那么select #就会触发,如果没有数据返回,则select就不会被触发 input_list.append(conn) #将和这个客户端的连接的服务端的实例也加入到监听列表中,当客户端发送消息的 #时候,select就会被触发 message_queue[conn] = queue.Queue() #为这个连接的客户端单独创建一个独一无二的消息队列,用来保存客户端发送的消息。 else: #代表一个有数据的链接进来了,这个时候我就可以开始收数据了 #由于客户端连接进来时服务端接受客户端的连接请求,将这个客户端的服务端的 #也加入到监听列表中,这个客户端如果发送消息,则会触发select try: recv_data = obj.recv(1024) if recv_data: #客户端未断开 print("received {0} from client {1}".format(str(recv_data,encoding="utf-8"),addr)) #将收到的信息放入该客户端的队列中 message_queue[obj].put(recv_data) #此时也不能直接给客户端返回数据,因为一旦返回数据,就又可能造成阻塞,所有将回复操作放到output列表中,让select监听 if obj not in output_list: output_list.append(obj) except ConnectionResetError: input_list.remove(obj) del message_queue[obj] print("client {0} is disconnected".format(addr)) for sendobj in stdoutput: #这里处理的是返回的消息,output_list是我们自己维护的,我们自己往里面放数据 try: if not message_queue[sendobj].empty(): #如果消息队列中有消息,从消息队列中获取要发送的消息 send_data = message_queue[sendobj].get() #从该客户端对象的消息队列中获取消息 sendobj.sendall(send_data) else: output_list.remove(sendobj) #将监听移除等待瞎猜疑客户端发送消息 except ConnectionResetError: #客户端连接断开 del message_queue[sendobj] output_list.remove(sendobj) print("Client {0} disconnected".format(addr)) for obj in stderr: #如果出错的处理 # print() input_list.remove(obj) if obj in output_list: output_list.remove(obj) obj.close() del message_queue[obj]