Python-Day9
select服务器:
1 #!/usr/bin/env pyhton3 2 # -*- coding:utf-8 -*- 3 __author__ = 'songge1209' 4 5 import select 6 import socket 7 import sys 8 import queue 9 10 #生成socket句柄,指定socket.AF_INET为网络通信,socket.SOCK_STREAM基于TCP连接,不指定默认也是这两个 11 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 12 #设置不阻塞,False和0为不阻塞,True和1为阻塞 13 server.setblocking(False) 14 15 #以元组形式将服务器地址和端口赋值给变量server_address 16 server_address = ("localhost",10000) 17 #打印错误 18 print(sys.stderr,"starting up on %s port %s" % server_address) 19 #为服务器绑定IP和端口 20 server.bind(server_address) 21 22 #指定客服端最大连接数为5 23 server.listen(5) 24 25 #定义输入列表,把socket句柄放入列表 26 inputs = [server] 27 28 #定义输出列表,初始为空 29 outputs = [] 30 31 #定义消息队列,初始为空字典 32 message_queues = {} 33 #定义while循环,输入列表为空时,循环结束 34 while inputs: 35 36 #打印信息 37 print("\nwaiting for the next event") 38 #调用select模块的select方法监控输入,输出列表,并赋值给可读,可写,错误列表 39 readable,writeable,exceptional = select.select(inputs,outputs,inputs) 40 41 #for循环可读列表 42 for s in readable: 43 44 #若可读列表中元素是sockect句柄,表示用新连接 45 if s is server: 46 #接受新连接 47 connection,client_address = s.accept() 48 #打印连接客户端地址 49 print("new connection from ",client_address) 50 #连接设置为不阻塞 51 connection.setblocking(False) 52 #把连接追加到输入列表,下次while循环时select监控连接状态 53 inputs.append(connection) 54 #在消息队列字典中,以连接为KEY,生成一个独立的消息队列为值 55 message_queues[connection] = queue.Queue() 56 57 #不是server,代表某连接有数据发来 58 else: 59 #接收数据赋值给data 60 data = s.recv(1024).decode("utf8") 61 #如果有数据 62 if data: 63 #打印数据, s.getpeername()返回客户端地址和端口;(s.getsockname()返回本地服务器地址和端口) 64 print(sys.stderr,"received %s from %s " % (data, s.getpeername())) 65 #若直接返回会阻塞其他连接进来,所以先不返回,把数据赋值给该连接的消息队列 66 message_queues[s].put(data) 67 68 #连接不在输出列表时: 69 if s not in outputs: 70 #把连接追加到输出列表 71 outputs.append(s) 72 #没有接收到数据,可能是出错了 73 else: 74 #打印关闭该连接信息 75 print("closing",client_address,"after reading not data") 76 #出错了就需要关闭连接,同时清除掉这个连接的注册信息,如果在输出列表 77 if s in outputs: 78 #就从列表中删除掉 79 outputs.remove(s) 80 #输入列表中也把此连接删除 81 inputs.remove(s) 82 #关闭连接 83 s.close() 84 #消息队列字典中也清除掉此链接信息 85 del message_queues[s] 86 87 #循环可写列表: 88 for s in writeable: 89 #判断下面执行有无异常 90 try: 91 #从该连接的消息队列取数据 92 next_msg = message_queues[s].get_nowait() 93 #若该连接的消息队列为空时,捕获执行以下操作 94 except queue.Empty: 95 #打印此连接的信息和队列为空 96 print("output queue for",s.getpeername(),"is empty") 97 #清除输出列表中的此链接 98 outputs.remove(s) 99 #不为空,取到数据 100 else: 101 #打印发送数据信息和客户端信息 102 print("sending %s to %s " % (next_msg,s.getpeername())) 103 #发送给客户端 104 s.send(next_msg.encode("utf8")) 105 106 #当客户端断开连接,会产生错误,循环错误列表 107 for s in exceptional: 108 #打印错误信息 109 print("handling exceptional condition for", s.getpeername()) 110 #删除输入列表中的此连接 111 inputs.remove(s) 112 #如果此连接在输出列表中 113 if s in outputs: 114 #删除此连接 115 outputs.remove(s) 116 #关闭这个连接 117 s.close() 118 #如果在消息队列字典中有这个连接 119 if message_queues[s]: 120 #删除这个连接 121 del message_queues[s]
select客户端:
1 #!/usr/bin/env pyhton3 2 # -*- coding:utf-8 -*- 3 __author__ = 'songge1209' 4 5 import socket 6 import sys 7 8 #定义信息列表 9 messages = ["This is the message.", 10 "It will be sent", 11 "in parts.", 12 ] 13 14 #指定要连接的服务器地址和端口 15 server_address = ("localhost",10000) 16 17 #定义一个连接列表,指定连接方式,创建连接 18 socks = [socket.socket(socket.AF_INET,socket.SOCK_STREAM), 19 socket.socket(socket.AF_INET,socket.SOCK_STREAM), 20 ] 21 22 #如果有错误,输出错误 23 print(sys.stderr,"connection to %s port %s" % server_address) 24 #循环连接列表 25 for s in socks: 26 #连接服务器 27 s.connect(server_address) 28 29 #循环信息列表 30 for message in messages: 31 #循环连接服务器列表 32 for s in socks: 33 #如果有错误,输出错误信息,s.getsockname()返回本地地址和端口 34 print(sys.stderr,"%s: sending %s" % (s.getsockname(),message)) 35 #给服务器发送信息 36 s.send((message).encode("utf8")) 37 38 #循环连接服务器列表 39 for s in socks: 40 #接收数据赋值给data 41 data = s.recv(1024).decode("utf8") 42 #如果有错误,输出错误信息 43 print(sys.stderr,"%s: received %s" % (s.getsockname(),message)) 44 #如果没有接收到数据 45 if not data: 46 #打印关闭信息 47 print(sys.stderr,"closing socket %s" ,s.getsockname()) 48 #关闭连接 49 s.close()