IO 多路复用

IO (input/output) 多路复用
socket就是网络传输,socket也算是网络文件传输操作

所以socket也算是IO操作的一种
而 IO就是通过一种机制,可以监听多个文件描述符(文件句柄)一旦文件句柄出现变化,即可感知到。
 1 # socket监听多个端口
 2 import socket
 3 import select
 4 HOST = ('127.0.0.1', 8002)
 5 
 6 sk1 = socket.socket()
 7 sk1.bind(('127.0.0.1', 8001))
 8 sk1.listen(5)
 9 
10 sk2 = socket.socket()
11 sk2.bind(('127.0.0.1', 8002))
12 sk2.listen(5)
13 
14 sk3 = socket.socket()
15 sk3.bind(('127.0.0.1', 8003))
16 sk3.listen(5)
17 inputs = [sk1]
18 outputs = []
19 massage_dic = {}
20 
21 while True:
22     # 第一个参数[sk1,sk2,sk3],select 内部自动监听sk1,sk2,sk3,三个对象,一旦某个句柄发生变化,就会把发生变化的对象加入到l_list中
23     # 第二个参数[]中 不管有没有变化,只有有值,就把值导入到 w_list
24     # 第三个参数[sk1,sk2,sk3],如果谁发生错误了,就会导入 e_list中
25     r_list, w_list, e_list = select.select(inputs, outputs, inputs, 3)
26     print(r_list)
27 
28     for sk_conn in r_list:
29         # 如果说这个sk_conn和sk1 相同的话,就把这个conn添加到inputs中,这样在下次再循环的时候,也会监听这个conn的连接实例
30         if sk1 == sk_conn:
31             conn,address = sk1.accept()
32             inputs.append(conn)
33             # 将 此conn(客户端链接实例)作为key存到字典中,value的值为该conn连接实例 发来的消息。
34             massage_dic[conn] = []
35         else:
36             '''
37             data_bytes = sk_conn.recv(1024)
38             if data_bytes:
39 
40                 data_str = str(data_bytes, encoding='utf-8')
41                 sk_conn.sendall(bytes(data_str + '好', encoding='utf-8'))
42 
43             else:
44                 inputs.remove(sk_conn)
45             (客户端停止链接后,会发送空的字符到服务端,在windows上会出现报错 ,而在Linux和mac下是不会报错的)
46             '''
47             # 如果说不是sk1,那么之前已经把所连接的conn实例添加到inputs中做实时监听,所以只要conn发生变化就会将conn添加到r_list中
48             try:
49                 data_bytes = sk_conn.recv(1024)
50             # 如果说 conn客户端那边断开连接后,接受的消息就会出现异常,就把出现异常的conn 从inputs中移除
51             except Exception as e:
52                 inputs.remove(sk_conn)
53             else:
54                 # 如果正常的接受消息就把该 conn 放到 outputs 中,outputs中存储的就只有给服务端发来消息的客户端实例。
55                 outputs.append(sk_conn)
56                 # 将客户端发来的消息,添加到massage相应的conn中
57                 massage_dic[conn].append(data_bytes)
58     # 再次循环后,w_list中存储的是 给服务端发消息的(客户端实例),massage[conn]也存储的发送的消息信息。
59     for send_conn in w_list:
60         # 每个发送消息的信息为
61         result_str = str(massage_dic[send_conn][0],encoding='utf-8')
62         # 获取到该客户端发送的什么消息,我们岂不是想干啥就干啥!
63         send_conn.sendall(bytes(result_str+'12312313',encoding='utf-8'))
64         # 发送完毕之后,要把该元素从outputs中删除掉,等下次再发消息的时候再来吧
65         outputs.remove(send_conn)
66         del massage_dic[send_conn][0]  #这里可以继续优化,利用queue
67 
68     for sk_conn in e_list:
69         inputs.remove(sk_conn)
70   
71 #     select poll epoll
72 #     IO 多路复用 是系统底层调用
73 #     最开始的时候都用select(1024个),内部进行for循环检测。
74 #     poll 是对select的优化,内部底层还是通过for循环来实现的
75 #     epoll 是对IO的革新,底层放弃for循环,使用异步的方法,谁有变化的话,谁就通知。
76 #   socketserver 就是由 sockett + select + 多线程 来实现的;


 


posted @ 2017-06-19 22:14  LeeeetMe  阅读(159)  评论(0编辑  收藏  举报