python并发,阻塞、非阻塞、epoll

01 阻塞服务端

特征:1对1,阻塞。
 1 import socket
 2 
 3 server = socket.socket()        #生成套接字对象
 4 server.bind(('0.0.0.0', 8000))    #套接字绑定ip和端口,变为监听套接字
 5 server.listen(5)                    #开始监听
 6 
 7 while True:
 8     conn, addr = server.accept()        #建立连接,生成对等套接字
 9     print('用户连接:', addr)
10     while True:
11         try:
12             data = conn.recv(1024)
13             if data == b'Q' or data == b'q':
14                 print('用户退出:', addr)
15                 break
16             else:
17                 print('收到的消息:', data.decode())
18                 conn.send(data)
19         except Exception as e:
20             print(e)
21             conn.close()
22             break

02 非阻塞服务端

特征:1对多,轮询,非阻塞,占用资源多。
 1 import socket
 2 
 3 server = socket.socket()        #创建套接字
 4 server.setblocking(False)       #把套接字设置为非阻塞
 5 server.bind(('0.0.0.0', 8001))  #绑定IP和端口
 6 server.listen(5)                #监听端口
 7 
 8 
 9 all_connection = []             #保存已经连接的客户
10 while True:
11     #只管连接的事情
12     try:
13         conn, addr = server.accept()    # 建立连接,没有就抛出异常
14         conn.setblocking(False)         #设置非阻塞
15         print('用户连接:', addr)
16         all_connection.append(conn)
17     except Exception as e:
18         pass
19 
20 
21     #处理已经连接用户的消息
22     handle = all_connection.copy()  #完全拷贝了列表
23     for connection in handle:
24         try:
25             recv_data = connection.recv(1024)
26             if recv_data:
27                 print(recv_data.decode())
28                 connection.send(recv_data)
29             else:                               #客户端消息处理完了,已经断开了连接
30                 print('断开连接', connection)
31                 connection.close()
32                 all_connection.remove(connection)       #从客户列表里移除断开连接的客户
33         except Exception as e:
34             pass

03 epoll服务端

特征:1对多,通知机制,非阻塞,占用资源少;
epoll:注册惰性事件回调。
 1 import selectors #调用epoll的模块
 2 import socket
 3 
 4 epoll = selectors.EpollSelector()   #生成一个epoll
 5 server = socket.socket()            #生成套接字
 6 server.bind(('', 8082))  #参数1‘’与‘0.0.0.0’等价,表示ip都可接入
 7 server.listen(100)
 8 
 9 
10 #回调函数
11 def create_conneciton(server):
12     #百分百有人连接,不会阻塞
13     conn, addres = server.accept()  #生成对等连接套接字
14 
15 
16     #处理消息的函数注册
17     epoll.register(conn, selectors.EVENT_READ, read_data)
18     return conn
19 
20 
21 
22 #回调函数   处理消息
23 def read_data(conn):
24 
25     data = conn.recv(1024)
26     if data:
27         print(data)
28         conn.send(data)
29     else:
30         epoll.unregister(conn)  #删掉注册事件
31 
32 
33 #1
34 #把监听套接字和生成对等套接字的函数注册到read事件(有用户连接)
35 epoll.register(server, selectors.EVENT_READ, create_conneciton)
36 
37 
38 #2
39 while True:      #事件循环
40     events = epoll.select()  #去操作系统查询
41 
42     for key,mask in events:
43         sock = key.fileobj      #连接客户端的套接字
44         callback = key.data     #回调函数
45 
46         #read_data(conn),   create_conneciton(server)
47         callback(sock)      #调用函数

04 客户端

测试服务端。
 1 import socket
 2 
 3 client = socket.socket()
 4 client.connect(('127.0.0.1', 8082))
 5 
 6 while True:
 7     data = input('输入数据:')
 8     client.send(data.encode())
 9     recv_data = client.recv(1024)
10     print(recv_data.decode())