1.你往output里面放什么,下次循环就出什么。
2.
1.服务器端:实现了收和发的分开进行
import select,socket,queue server=socket.socket() server.bind(('localhost',9000)) server.listen(1024) server.setblocking(False) msg_dic={} #定义一个空字典 inputs=[server,] outputs=[] while True: readable,writeable,exceptional=select.select(inputs,outputs,inputs) print(readable,writeable,exceptional) for r in readable: if r is server: conn,addr=server.accept() print('来了个新链接',addr) inputs.append(conn) msg_dic[conn]=queue.Queue() #初始化一个队列,后面存要返回给客户端的数据 else: data=r.recv(1024) print('收到数据',data) msg_dic[r].put(data) #把要发的数据存在字典里面,等下次循环的时候发。 outputs.append(r) #放入返回的链接队列里 #r.send(data) for w in writeable: #要返回给客户端的链接列表 data_to_client=msg_dic[w].get() w.send(data_to_client) #返回给客户端源数据。这样收和发就分开了。 outputs.remove(w) #确保下次循环的时候writeable不返回这个已经处理完的链接。 for e in exceptional: if e in outputs: outputs.remove(e) inputs.remove(e) del msg_dic[e]
客户端:
import socket s=socket.socket() s.connect(('localhost',9000)) while True: msg=bytes(input(">>:"),encoding='utf8') s.sendall(msg) data=s.recv(1024) print('Received',repr(data)) s.close()
运行结果:当一个客户端断开时,服务器端也会报错。下面的完整版摘自老师的博客。
2. 服务器端
#_*_coding:utf-8_*_ __author__ = 'Alex Li' import select import socket import sys import queue server = socket.socket() server.setblocking(0) server_addr = ('localhost',10000) print('starting up on %s port %s' % server_addr) server.bind(server_addr) server.listen(5) inputs = [server, ] #自己也要监测呀,因为server本身也是个fd outputs = [] message_queues = {} while True: print("waiting for next event...") readable, writeable, exeptional = select.select(inputs,outputs,inputs) #如果没有任何fd就绪,那程序就会一直阻塞在这里 for s in readable: #每个s就是一个socket if s is server: #别忘记,上面我们server自己也当做一个fd放在了inputs列表里,传给了select,如果这个s是server,代表server这个fd就绪了, #就是有活动了, 什么情况下它才有活动? 当然 是有新连接进来的时候 呀 #新连接进来了,接受这个连接 conn, client_addr = s.accept() print("new connection from",client_addr) conn.setblocking(0) inputs.append(conn) #为了不阻塞整个程序,我们不会立刻在这里开始接收客户端发来的数据, 把它放到inputs里, 下一次loop时,这个新连接 #就会被交给select去监听,如果这个连接的客户端发来了数据 ,那这个连接的fd在server端就会变成就续的,select就会把这个连接返回,返回到 #readable 列表里,然后你就可以loop readable列表,取出这个连接,开始接收数据了, 下面就是这么干 的 message_queues[conn] = queue.Queue() #接收到客户端的数据后,不立刻返回 ,暂存在队列里,以后发送 else: #s不是server的话,那就只能是一个 与客户端建立的连接的fd了 #客户端的数据过来了,在这接收 data = s.recv(1024) if data: print("收到来自[%s]的数据:" % s.getpeername()[0], data) message_queues[s].put(data) #收到的数据先放到queue里,一会返回给客户端 if s not in outputs: outputs.append(s) #为了不影响处理与其它客户端的连接 , 这里不立刻返回数据给客户端 else:#如果收不到data代表什么呢? 代表客户端断开了呀 print("客户端断开了",s) if s in outputs: outputs.remove(s) #清理已断开的连接 inputs.remove(s) #清理已断开的连接 del message_queues[s] ##清理已断开的连接 for s in writeable: try : next_msg = message_queues[s].get_nowait() except queue.Empty: print("client [%s]" %s.getpeername()[0], "queue is empty..") outputs.remove(s) else: print("sending msg to [%s]"%s.getpeername()[0], next_msg) s.send(next_msg.upper()) for s in exeptional: print("handling exception for ",s.getpeername()) inputs.remove(s) if s in outputs: outputs.remove(s) s.close() del message_queues[s] select socket server
客户端:
#_*_coding:utf-8_*_ __author__ = 'Alex Li' import socket import sys messages = [ b'This is the message. ', b'It will be sent ', b'in parts.', ] server_address = ('localhost', 10000) # Create a TCP/IP socket socks = [ socket.socket(socket.AF_INET, socket.SOCK_STREAM), socket.socket(socket.AF_INET, socket.SOCK_STREAM), ] # Connect the socket to the port where the server is listening print('connecting to %s port %s' % server_address) for s in socks: s.connect(server_address) for message in messages: # Send messages on both sockets for s in socks: print('%s: sending "%s"' % (s.getsockname(), message) ) s.send(message) # Read responses on both sockets for s in socks: data = s.recv(1024) print( '%s: received "%s"' % (s.getsockname(), data) ) if not data: print(sys.stderr, 'closing socket', s.getsockname() ) select socket client