# 利用python的select模块实现简单的Socket Sever
#实现多用户访问,再次基础上可以实现FTP Server应用程序
# 发布目的,在于解决了客户端强行终止时,服务器端也跟着程序终止
# 程序的关键在:读就是读,写就是写 ,不要读写混着来
# 代码如下:
Server
1 __author__ = 'Stone' 2 # -*- coding: UTF-8 -*- 3 # !/usr/bin/env python3 4 import socket 5 import queue 6 import select 7 HOST = '0.0.0.0' 8 PORT = 8000 9 s = socket.socket() 10 s.bind((HOST,PORT)) 11 s.listen(500) 12 # 设定关闭程序后,能马上释放服务器的端口,供后续程序使用 13 s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 14 s.setblocking(0) # 设置为非阻塞模式 15 # 设置列表,新建、发送、异常 16 inputs = [] 17 outputs = [] 18 #exceptions = [] 19 # 存放信息 20 msg_dic = {} 21 inputs.append(s) # 把自身加进去,侦听是否有新连接 22 while True: 23 readable,writable,exceptional = select.select(inputs,outputs,inputs) # select 会阻塞socket 22 25 for r in readable: 26 if r is s: 27 # 说明有新连接过来 28 conn,addr = s.accept() 29 print("新连接:",addr) 30 conn.setblocking(0) # 把单个连接也设置为非阻塞模式,比如:某个连接接收的文件比较大,将会一直占用着(别的程序没机会处理);设置为非阻塞后,可以等着下次for循环继续接收 31 inputs.append(conn) 32 msg_dic[conn] = queue.Queue() # 为每个连接创建消息队列 33 else: 34 # 说明有连接是活动的 35 try: 36 data = r.recv(1024) 37 if data: 38 print("接收到了数据:",data.decode('utf-8')) 39 # 放进消息队列 40 msg_dic[r].put(data) 41 if r not in outputs: 42 outputs.append(r) # 并放入发送数据列表 43 else: 44 # 连接断开 45 print("客户端断开连接") 46 if r in outputs: 47 outputs.remove(r) 48 inputs.remove(r) 49 del msg_dic[r] 50 except socket.error: # 解决问题(出现客户端异常断开,服务器也跟着断开),后面不做任何处理,留给exceptional做处理 51 pass 52 53 for w in writable: 54 try: 55 send_msg = msg_dic[w].get_nowait() 56 except queue.Empty: 57 print("client [%s]"% w.getpeername()[0],"queue is empty...") 58 outputs.remove(w) 59 else: 60 print("sending message to [%s]"% w.getpeername()[0],send_msg) 61 w.send(send_msg) 62 outputs.remove(w) # 防止再次执行时,发生empty的异常 63 64 for e in exceptional: 65 if e in outputs: 66 outputs.remove(e) 67 inputs.remove(e) 68 e.close() 69 del msg_dic[e] 70 s.close()
Client:
1 __author__ = 'Stone' 2 # -*- coding: UTF-8 -*- 3 # !/usr/bin/env python3 4 import socket 5 HOST = 'localhost' 6 PORT = 8000 7 s_client = socket.socket() 8 s_client.connect((HOST,PORT)) 9 while True: 10 data = input('>>:').strip() 11 if not data: 12 continue 13 s_client.send(data.encode('utf-8')) 14 recv = s_client.recv(1024) 15 print(recv) 16 #break # 测试,作为客户端自动离开 17 s_client.close()