1 server_duan.py
1 import socket 2 from socket import SOL_SOCKET, SO_REUSEADDR 3 import commen 4 import os 5 6 7 sk = socket.socket() 8 sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 9 sk.bind(('127.0.0.1', 8081)) # '127.0.0.1':本地回环地址; 10 sk.listen(3) # 设定"可以等待链接的客户端最大数量" 11 12 # 服务端下载功能 13 def s_down(c_or_s): 14 # 1 接收电影报头 15 mv_header = commen.recv_header(c_or_s) 16 17 # 2 接收电影 18 # 2.1 获取电影名和电影大小 19 mv_name = mv_header.get('mv_name') 20 mv_size = mv_header.get('mv_size') 21 # 2.2 接收电影 22 commen.down_file(c_or_s, mv_name, mv_size) 23 24 # 服务端上传功能 25 def s_up(c_or_s): 26 # 输入/获取电影资源地址(请手动复制地址替换url) 27 source_mv_addr = r'url' 28 mv_list = os.listdir(source_mv_addr) 29 # 发送"电影列表"给客户端 30 commen.send_header(c_or_s, mv_list) # # 需要sock 31 # 接收客户端选择的电影编号 32 choice_mv_num = commen.recv_header(c_or_s) # # 需要sock 33 # 校验客户端软件是否发生异常 34 # 正常情况下,客户端发送过来的电影编号都是存在的(客户端已校验过),若不存在说明客户端代码异常 35 if not commen.exist_choice_num(choice_mv_num, mv_list): 36 war_meg = '文件被破坏,请重新下载客户端' 37 print('客户端代码被修改,发送告知: %s' % war_meg) 38 commen.send_header(c_or_s, war_meg) # # 需要sock 39 return print('等待客户端下载完成后重新链接') 40 # 运行到此步,说明电影编号存在 41 # 上传电影到客户端 42 43 # 1) 制作电影报头 44 # 获取制作报头需要的信息: 电影名和电影地址 45 mv_name = mv_list[int(choice_mv_num)-1] 46 mv_path = os.path.join(source_mv_addr, mv_name) 47 # 制作 48 mv_header = {'mv_name': mv_name, 'mv_size': os.path.getsize(mv_path)} 49 # print(mv_header) 50 # 2) 发送电影报头 51 commen.send_header(c_or_s, mv_header) # 需要sock 52 # 3) 发送电影 53 commen.up_file(c_or_s, mv_name, mv_path) # 需要sock 54 55 56 # 主程序核心代码 57 def s_src(s_server): 58 func_dict = {'1': s_down, '2': s_up} 59 # 接收客户端的消息,获取客户端的需求: 是上传还是下载,然后做对应处理 60 func_choice = commen.recv_header(s_server) 61 if not func_choice.isdigit(): 62 return print('客户端软件损坏') 63 if func_choice not in func_dict: 64 return print('客户端软件损坏') 65 func = func_dict.get(func_choice) 66 # print(func) 67 func(s_server) 68 69 # 主程序 70 def s_run(): 71 while True: 72 sock, addr = sk.accept() 73 while True: 74 try: 75 s_src(sock) 76 except Exception: 77 print('客户端异常断开,正在等待其他客户端接入...') 78 break 79 80 81 s_run()View Code
2 client_duan.py
1 import socket 2 import os 3 import commen 4 5 client = socket.socket() 6 client.connect(('127.0.0.1', 8081)) 7 8 # 客户端上传功能 9 def c_up(): 10 # 获取本地视频文件地址(这里需手动输入) 11 mv_dir_path = r'E:\BaiduNetdiskDownload\entertainment\video' 12 # 根据地址获取电影列表 13 mv_list = os.listdir(mv_dir_path) 14 # 展示电影条目 15 print('电影清单>>>:') 16 for i, j in enumerate(mv_list): 17 print(i + 1, j) 18 while True: 19 # 1 选择要上传的电影编号 20 choice_num = input('请输入想要上传的电影编号>>>:').strip() 21 # 2 判断电影编号是否存在,不存在,重新输入 22 if not commen.exist_choice_num(choice_num, mv_list): 23 continue 24 # 运行到此步说明电影编号存在 25 # 3 发送电影 26 27 # 3.1 制作报头 28 # 3.11 获取报头必要信息 29 # 获取电影名字 30 mv_name = mv_list[int(choice_num) - 1] 31 # 获取电影地址 32 mv_path = os.path.join(mv_dir_path, mv_name) 33 # 启发: 两行代码一般没必要定义成函数 34 # 3.12 制作 35 mv_header = {'mv_name': mv_name, 'mv_size': os.path.getsize(mv_path)} 36 # 3.2 发送报头 37 commen.send_header(client, mv_header) 38 # 3.3 发送电影 39 commen.up_file(client, mv_name, mv_path) 40 break 41 42 # 客户端下载功能 43 def c_down(): 44 # 接收客户端发来的电影列表信息 45 mv_list = commen.recv_header(client) 46 # 将电影以"枚举"方式展示给客户端 47 for i, j in enumerate(mv_list): 48 print(i + 1, j) 49 # 选择要下载的电影编号,以及后续下载相关 50 while True: 51 # 1 输入想要下载的电影编号 52 choice_num = input('请输入想要下载的电影编号>>>:').strip() 53 # 2 判断电影编号是否存在,若不存在,则重新输入电影编号 54 if not commen.exist_choice_num(choice_num, mv_list): 55 continue 56 # 3 输入的电影编号存在, 将电影编号发送给服务端 57 commen.send_header(client, choice_num) 58 59 # 4 接收服务端的电影数据 60 # 1)接收电影报头 61 mv_header = commen.recv_header(client) 62 # 2)接收电影 63 mv_name = mv_header.get('mv_name') 64 mv_size = mv_header.get('mv_size') 65 commen.down_file(client, mv_name, mv_size) 66 break 67 68 # 主程序 69 def c_run(): 70 func_dict = {'1': c_up, '2': c_down} # 注意函数名后无小括号,否则检查语法阶段就直接执行函数了 71 while True: 72 func_choice = input("请选择想要的功能:\r\n" 73 "1: 上传电影\r\n" 74 "2: 下载电影\r\n>>>:" 75 ).strip() 76 77 if not func_choice.isdigit(): 78 print('输入不合法') 79 continue 80 if func_choice not in func_dict: 81 print('无该功能') 82 continue 83 func = func_dict.get(func_choice) 84 print(func) 85 # print('======') 86 # 将客户端选择的功能编号发送给服务端 87 commen.send_header(client, func_choice) 88 func() 89 90 91 c_run()View Code
3 commen.py
1 import json 2 import struct 3 4 # 发送报头,其实就是发送了某一种数据类型的数据(如一个字典) 5 # 所以,当你想发送一个字典或列表等任意非文件的数据,都可以用如下函数发送.一步到位. 6 def send_header(c_or_s, header): 7 json_str_bt = json.dumps(header) 8 # 打包报头 9 pack_bt = struct.pack('i', len(json_str_bt)) 10 # 发送打包的报头 11 c_or_s.send(pack_bt) 12 # 发送报头 13 c_or_s.send(json_str_bt.encode('utf-8')) 14 15 def up_file(c_or_s, file_name, file_path): 16 with open(file_path, 'rb') as f: 17 for line in f: 18 c_or_s.send(line) 19 print('>>>:"%s"上传完了' % file_name) 20 21 def recv_header(c_or_s): 22 # 接收打包的报头 23 pack_bt = c_or_s.recv(4) 24 # 解压报头 25 bt_size = struct.unpack('i', pack_bt)[0] 26 # 接收报头 27 bytes_bt = c_or_s.recv(bt_size) 28 # print(type(bytes_bt), bytes_bt.decode('utf-8')) 29 # 将报头转换成原数据类型 30 orig_header = json.loads(bytes_bt) 31 return orig_header 32 33 def down_file(c_or_s, file_name, file_size): 34 with open(file_name, 'wb') as f: 35 recv_size = 0 36 while recv_size < file_size: 37 tmp_data = c_or_s.recv(1024) 38 recv_size += len(tmp_data) 39 f.write(tmp_data) 40 print('>>>:"%s"下载完了' % file_name) 41 42 def exist_choice_num(choice_num, mv_list): 43 if not choice_num.isdigit(): 44 print('输入无效!') 45 return False 46 choice_num = int(choice_num) 47 if choice_num not in range(1, len(mv_list) + 1): 48 print('您输入的编号不存在!') 49 return False 50 return TrueView Code