一、服务端代码:
1 import socket 2 import subprocess 3 import struct 4 import json 5 import os 6 7 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 9 phone.bind(('127.0.0.1', 8081)) # 0-65535:0-1024给操作系统使用 10 phone.listen(5) 11 12 print('starting......') 13 while True: # 链接循环 14 conn, client_addr = phone.accept() 15 print(client_addr) 16 17 while True: # 通信循环 18 try: 19 # 1、收命令 20 res = conn.recv(8096) # b'get a.txt' 21 if not res: # 适用于linux操作系统 22 break 23 24 # 2、解析命令,提取相应命令参数 25 cmds = res.decode('utf-8').split() # ['get', 'a.txt'] 26 filename = cmds[1] 27 # 3、以读的方式打开文件,读取文件内容发送到客户端 28 29 # 第一步:制作固定长度的报头 30 header_dic = { 31 'filename': filename, 32 'md5': 'xxdxx', 33 'file_size': os.path.getsize(filename) 34 } 35 36 header_json = json.dumps(header_dic) 37 header_bytes = header_json.encode('utf-8') 38 39 # 第二步:先发送报头的长度 40 conn.send(struct.pack('i', len(header_bytes))) 41 42 # 第三步:把包头发送给客户端 43 conn.send(header_bytes) 44 45 # 第三步:再发送真实的数据 46 with open(filename, 'rb') as f: 47 # conn.send(f.read()) 48 for line in f: 49 conn.send(line) 50 51 except ConnectionResetError: # 适用于Windows操作系统 52 break 53 54 conn.close() 55 56 phone.close()
二、客户端代码:
1 import socket 2 import struct 3 import json 4 5 6 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 8 phone.connect(('127.0.0.1', 8081)) 9 10 while True: 11 # 1、发命令 12 cmd = input('>>:').strip() # get a.txt 13 if not cmd: 14 continue 15 phone.send(cmd.encode('utf-8')) 16 17 # 2、以写的方式打开一个新文件,接收服务器端发来的文件内容写入客户的新文件 18 19 # 第一步:先收报头的长度 20 obj = phone.recv(4) 21 header_size = struct.unpack('i', obj)[0] 22 23 # 第二步:再收报头 24 header_bytes = phone.recv(header_size) 25 26 # 第三步:从报头中解析出对真实数据的描述信息 27 header_json = header_bytes.decode('utf-8') 28 header_dic = json.loads(header_json) 29 print(header_dic) 30 total_size = header_dic['file_size'] 31 filename = header_dic['filename'] 32 33 # 第四步: 接收真实的数据 34 with open(filename, 'wb') as f: 35 recv_size = 0 36 while recv_size < total_size: 37 line = phone.recv(1024) 38 f.write(line) 39 recv_size += len(line) 40 41 42 phone.close()
先启动服务端,再启动客户端,然后在客户端执行 get 1.txt, get test.py 都显示下载成功:
客户端打印字典信息为:
1 >>:get 1.txt 2 {'filename': '1.txt', 'md5': 'xxdxx', 'file_size': 8} 3 >>:get test.py 4 {'filename': 'test.py', 'md5': 'xxdxx', 'file_size': 60} 5 >>:
以上代码已经实现了客户端从服务端下载文件的功能,如果想把数据从客户端上传到服务端,则把服务端和客户端代码
做相应调整即可。
如果server提供下载文件夹share,client指定下载文件夹download,
客户端和服务端代码改为:
1 客户端代码: 2 import socket 3 import struct 4 import json 5 6 download_dir = r'C:Usersxu516PycharmProjectsPython全栈开发第三模块网络编程 6_文件传输clientdownload' 7 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 9 phone.connect(('127.0.0.1', 8081)) 10 11 while True: 12 # 1、发命令 13 cmd = input('>>:').strip() # get a.txt 14 if not cmd: 15 continue 16 phone.send(cmd.encode('utf-8')) 17 18 # 2、以写的方式打开一个新文件,接收服务器端发来的文件内容写入客户的新文件 19 20 # 第一步:先收报头的长度 21 obj = phone.recv(4) 22 header_size = struct.unpack('i', obj)[0] 23 24 # 第二步:再收报头 25 header_bytes = phone.recv(header_size) 26 27 # 第三步:从报头中解析出对真实数据的描述信息 28 header_json = header_bytes.decode('utf-8') 29 header_dic = json.loads(header_json) 30 print(header_dic) 31 total_size = header_dic['file_size'] 32 filename = header_dic['filename'] 33 34 # 第四步: 接收真实的数据 35 with open('%s\%s' % (download_dir, filename), 'wb') as f: 36 recv_size = 0 37 while recv_size < total_size: 38 line = phone.recv(1024) 39 f.write(line) 40 recv_size += len(line) 41 print('总大小:%s 已下载大小:%s' % (total_size, recv_size)) 42 43 44 phone.close() 45 46 服务端代码: 47 import socket 48 import subprocess 49 import struct 50 import json 51 import os 52 53 share_dir = r'C:Usersxu516PycharmProjectsPython全栈开发第三模块网络编程 6_文件传输servershare' 54 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 55 # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 56 phone.bind(('127.0.0.1', 8081)) # 0-65535:0-1024给操作系统使用 57 phone.listen(5) 58 59 print('starting......') 60 while True: # 链接循环 61 conn, client_addr = phone.accept() 62 print(client_addr) 63 64 while True: # 通信循环 65 try: 66 # 1、收命令 67 res = conn.recv(8096) # b'get a.txt' 68 if not res: # 适用于linux操作系统 69 break 70 71 # 2、解析命令,提取相应命令参数 72 cmds = res.decode('utf-8').split() # ['get', 'a.txt'] 73 filename = cmds[1] 74 # 3、以读的方式打开文件,读取文件内容发送到客户端 75 76 # 第一步:制作固定长度的报头 77 header_dic = { 78 'filename': filename, 79 'md5': 'xxdxx', 80 'file_size': os.path.getsize('%s\%s' % (share_dir, filename)) 81 } 82 83 header_json = json.dumps(header_dic) 84 header_bytes = header_json.encode('utf-8') 85 86 # 第二步:先发送报头的长度 87 conn.send(struct.pack('i', len(header_bytes))) 88 89 # 第三步:把包头发送给客户端 90 conn.send(header_bytes) 91 92 # 第三步:再发送真实的数据 93 with open('%s\%s' % (share_dir, filename), 'rb') as f: 94 # conn.send(f.read()) 95 for line in f: 96 conn.send(line) 97 98 except ConnectionResetError: # 适用于Windows操作系统 99 break 100 101 conn.close() 102 103 phone.close()
客户端下载 get test.py 运行结果为:
1 >>:get test.py 2 {'filename': 'test.py', 'md5': 'xxdxx', 'file_size': 60} 3 总大小:60 已下载大小:60 4 >>: