代码改变世界

基于selectors实现客户端并发下载文件

2022-05-06 15:26  six-eight  阅读(31)  评论(0)    收藏  举报

主要知识点:

  yield 实现协程。 

server端源码:

 1 import selectors
 2 from socket import *
 3 import time
 4 import os
 5 import struct
 6 
 7 tasks = []
 8 
 9 def accept(sk):
10     conn, addr = sk.accept()
11     ds.register(conn, selectors.EVENT_READ, read)
12 
13 def get(conn, filename):
14     conn.send(struct.pack('i', os.path.getsize(filename)))
15     with open(filename, 'rb') as f:
16         while True:
17             data = f.read(1024)
18             if not data:
19                 break
20             conn.send(data)
21             yield
22 
23 def read(conn):
24     data = conn.recv(1024)
25     if not data:
26         ds.unregister(conn)
27         conn.close()
28     else:
29         cmd = data.decode('utf-8')
30         if cmd[0:3] == 'get':
31             c = get(conn, cmd[4:])
32             c.__next__()
33             tasks.append(c)
34 
35 if __name__ == '__main__':
36     sk = socket(AF_INET, SOCK_STREAM)
37     sk.bind(('127.0.0.1', 8082))
38     sk.listen(5)
39     ds = selectors.DefaultSelector()
40     ds.register(sk, selectors.EVENT_READ, accept)
41     while True:    
42         events = ds.select(timeout=0.05)
43         for key, mask in events:
44             key.data(key.fileobj)
45         for task in tasks:
46             try:
47                 task.send(1)
48             except StopIteration:
49                 tasks.remove(task)
50         
51         
52         
selectorsServer.py

client端源码:

 1 from socket import *
 2 import struct
 3 
 4 
 5 sk = socket(AF_INET, SOCK_STREAM)
 6 
 7 sk.connect(('127.0.0.1', 8082))
 8 
 9 while True:
10     msg = input(">>>>")
11     if not msg: continue
12     sk.send(msg.encode('utf-8'))
13     filesize = struct.unpack('i', sk.recv(4))[0]
14     has_receive = bytes()
15     while len(has_receive) < filesize:
16         has_receive += sk.recv(1024)
17     with open(msg[4:], 'wb') as f:
18         f.write(has_receive)
selectorsClient.py