傳輸文件簡單版
server端:
import socket import struct import json import os share_dir = r'C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\server\share' IP_PORT = ('127.0.0.1', 8999) def bytes2human(n): symbols = ('K', 'M', 'G', 'T', 'P', 'E') prefix = {} for i, s in enumerate(symbols): # << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4, # 10位就表示1024 即1 << 10=1024 就是2的n次方 prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f%s' % (value, s) return "%sB" % n def get(conn,file_name): # 3、以讀的方式打開文件,讀取文件內容發送給客戶端 # 第一步:制作固定長度的報頭 print('get') try: header_dict = { 'file_name': file_name, 'md5': 'xxx', 'file_size': os.path.getsize(os.path.join(share_dir, file_name)) } header_json = json.dumps(header_dict, ensure_ascii='False', indent=2) header_bytes = header_json.encode('utf-8') # 第二步:先發送報頭的長度 conn.send(struct.pack('i', len(header_bytes))) # 第三步:再發報頭 conn.send(header_bytes) # 第四步:再發送真實的數據 with open(os.path.join(share_dir, file_name), 'rb') as f: for line in f: conn.send(line) except Exception as e: print(e) def put(conn, file_name): """ 接收客戶端上傳文件 :param conn: :param file_name: :return: """ # 2、以寫的方式打開一個新文件,接收客戶端發來的文件的內容寫入服務端新文件 # 第一步:先收報頭的長度 header_len = conn.recv(4) header_size = struct.unpack('i', header_len)[0] # 第二步:再收報頭 header_json = conn.recv(header_size).decode('utf-8') # 第三步:從報頭中解析出對真實數據的描述信息 header_dict = json.loads(header_json) file_size = header_dict['file_size'] file_name = header_dict['file_name'] print(os.path.join(share_dir, file_name)) # 第四步:接收真實的數據,寫入文件 with open(os.path.join(share_dir, file_name), 'wb') as f: recv_size = 0 while recv_size < file_size: line = conn.recv(1024) f.write(line) recv_size += len(line) print('總大小:%s 已上傳大小:%s' % (bytes2human(file_size), bytes2human(recv_size))) def run(): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(IP_PORT) server.listen(5) print('starting...') while True: conn, addr = server.accept() print(addr) while True: try: # 1 收命令 res = conn.recv(1024) # b' get a.txt' if not res:break # 2、解析命令,提取相應命令參數 cmds = res.decode('utf-8').split() # [get, a.txt] if cmds[0] == 'get': get(conn, cmds[1]) # 下載文件 # file_name = cmds[1] elif cmds[0] == 'put': put(conn, cmds[1]) # 上傳文件 except ConnectionResetError: #適用於windows操作系統 break conn.close() server.close() if __name__ == '__main__': run()
client端
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import socket import struct import json import os share_dir = r'C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\client\download' IP_PORT = ('127.0.0.1', 8999) def bytes2human(n): symbols = ('K', 'M', 'G', 'T', 'P', 'E') prefix = {} for i, s in enumerate(symbols): # << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4, # 10位就表示1024 即1 << 10=1024 就是2的n次方 prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f%s' % (value, s) return "%sB" % n def get(client, file_name): # 2、以寫的方式打開一個新文件,接收服務端發來的文件的內容寫入客戶的新文件 # 第一步:先收報頭的長度 header_len = client.recv(4) header_size = struct.unpack('i', header_len)[0] # 第二步:再收報頭 header_json = client.recv(header_size).decode('utf-8') # 第三步:從報頭中解析出對真實數據的描述信息 header_dict = json.loads(header_json) file_size = header_dict['file_size'] file_name = header_dict['file_name'] print(os.path.join(share_dir, file_name)) # 第四步:接收真實的數據,寫入文件 with open(os.path.join(share_dir, file_name), 'wb') as f: recv_size = 0 while recv_size < file_size: line = client.recv(1024) f.write(line) recv_size += len(line) print('總大小:%s 已下載大小:%s' % (bytes2human(file_size), bytes2human(recv_size))) def put(client, file_name): # 向服務端上傳文件 print('put') try: if not os.path.isfile(os.path.join(share_dir, file_name)): print('file:%s is not exists' % os.path.join(share_dir, file_name)) return else: file_size = os.path.getsize(os.path.join(share_dir, file_name)) header_dict = { 'file_name': file_name, 'md5': 'xxx', 'file_size': file_size } header_json = json.dumps(header_dict, ensure_ascii='False', indent=2) header_bytes = header_json.encode('utf-8') # 第二步:先發送報頭的長度 client.send(struct.pack('i', len(header_bytes))) # 第三步:再發報頭 client.send(header_bytes) # 第四步:再發送真實的數據 with open(os.path.join(share_dir, file_name), 'rb') as f: for line in f: client.send(line) except Exception as e: print(e) def run(): client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(IP_PORT) while True: # 1、發命令 cmd = input('>> ').strip() # 'get a.txt' if not cmd:continue client.send(cmd.encode('utf-8')) if cmd.startswith('get'): get(client, cmd.split()[1]) elif cmd.startswith('put'): put(client, cmd.split()[1]) client.close() if __name__ == '__main__': run()
輸出結果
sever: starting... ('127.0.0.1', 19074) get get C:\Users\jingjing\PycharmProjects\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\server\share\3.jpeg 總大小:75.36K 已上傳大小:1.00K 總大小:75.36K 已上傳大小:2.00K …… 總大小:75.36K 已上傳大小:75.36K client: >> get 1.pptx C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\client\download\1.pptx 總大小:970.93K 已下載大小:1.00K 總大小:970.93K 已下載大小:2.00K …… 總大小:970.93K 已下載大小:970.93K >> put 3.jpeg put >>
傳輸文件優化版
server端:
import socket import struct import json import os class TCPServer: IP_PORT = ('127.0.0.1', 8999) request_queue_size = 5 allow_reuse_address = False max_packet_size = 8192 share_dir = r'C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\server\share' def __init__(self, address=IP_PORT, bind_and_activate=True): self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if bind_and_activate: try: self.server.bind(address) self.server.listen(self.request_queue_size) print('starting...') except Exception as e: self.server.close() raise e def get_request(self): """Get the request and client address from the socket. """ return self.server.accept() def run(self): while True: self.conn, self.client_addr = self.get_request() print('from client ', self.client_addr) while True: try: # 1 收命令 res = self.conn.recv(self.max_packet_size) # b' get a.txt' if not res: break # 2、解析命令,提取相應命令參數 cmds = res.decode('utf-8').split() # [get, a.txt] if hasattr(self, cmds[0]): func = getattr(self, cmds[0]) func(cmds[1]) except ConnectionResetError: # 適用於windows操作系統 break self.conn.close() self.server.close() def put(self, file_name): """ 接收客戶端上傳文件 :param conn: :param file_name: :return: """ print('get file %s' % file_name) # 2、以寫的方式打開一個新文件,接收客戶端發來的文件的內容寫入服務端新文件 # 第一步:先收報頭的長度 header_len = self.conn.recv(4) header_size = struct.unpack('i', header_len)[0] # 第二步:再收報頭 header_json = self.conn.recv(header_size).decode('utf-8') # 第三步:從報頭中解析出對真實數據的描述信息 header_dict = json.loads(header_json) file_size = header_dict['file_size'] file_name = header_dict['file_name'] print(os.path.join(self.share_dir, file_name)) # 第四步:接收真實的數據,寫入文件 with open(os.path.join(self.share_dir, file_name), 'wb') as f: recv_size = 0 while recv_size < file_size: line = self.conn.recv(self.max_packet_size) f.write(line) recv_size += len(line) rate = recv_size / file_size * 100 print('總大小:%s 已上傳:%%%.2f' % (self.bytes2human(file_size), rate)) @staticmethod def bytes2human(n): symbols = ('K', 'M', 'G', 'T', 'P', 'E') prefix = {} for i, s in enumerate(symbols): # << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4, # 10位就表示1024 即1 << 10=1024 就是2的n次方 prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f%s' % (value, s) return "%sB" % n def get(self, file_name): # 3、以讀的方式打開文件,讀取文件內容發送給客戶端 # 第一步:制作固定長度的報頭 print('send file %s' % file_name) try: header_dict = { 'file_name': file_name, 'md5': 'xxx', 'file_size': os.path.getsize(os.path.join(self.share_dir, file_name)) } header_json = json.dumps(header_dict, ensure_ascii='False', indent=2) header_bytes = header_json.encode('utf-8') # 第二步:先發送報頭的長度 self.conn.send(struct.pack('i', len(header_bytes))) # 第三步:再發報頭 self.conn.send(header_bytes) # 第四步:再發送真實的數據 with open(os.path.join(self.share_dir, file_name), 'rb') as f: for line in f: self.conn.send(line) except Exception as e: print(e) if __name__ == '__main__': s = TCPServer() s.run()
client端:
import socket import struct import json import os class TCPClient: IP_PORT = ('127.0.0.1', 8999) request_queue_size = 5 allow_reuse_address = False max_packet_size = 8192 share_dir = r'C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\client\download' def __init__(self, address=IP_PORT, connect=True): self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if connect: try: self.client.connect(address) except Exception as e: self.client.close() raise e def run(self): while True: # 1、發命令 inp = input('>> ').strip() # 'get a.txt' if not inp: continue self.client.send(inp.encode('utf-8')) cmd = inp.split() if hasattr(self, cmd[0]): func = getattr(self, cmd[0]) func(cmd[1]) client.close() @staticmethod def bytes2human(n): symbols = ('K', 'M', 'G', 'T', 'P', 'E') prefix = {} for i, s in enumerate(symbols): # << 左移” 左移一位表示乘2 即1 << 1=2,二位就表示4 即1 << 2=4, # 10位就表示1024 即1 << 10=1024 就是2的n次方 prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f%s' % (value, s) return "%sB" % n def get(self, file_name): # 2、以寫的方式打開一個新文件,接收服務端發來的文件的內容寫入客戶的新文件 # 第一步:先收報頭的長度 header_len = self.client.recv(4) header_size = struct.unpack('i', header_len)[0] # 第二步:再收報頭 header_json = self.client.recv(header_size).decode('utf-8') # 第三步:從報頭中解析出對真實數據的描述信息 header_dict = json.loads(header_json) file_size = header_dict['file_size'] file_name = header_dict['file_name'] print(os.path.join(self.share_dir, file_name)) # 第四步:接收真實的數據,寫入文件 with open(os.path.join(self.share_dir, file_name), 'wb') as f: recv_size = 0 while recv_size < file_size: line = self.client.recv(self.max_packet_size) f.write(line) recv_size += len(line) rate = recv_size / file_size * 100 print('總大小:%s 已下載:%%%.2f' % (self.bytes2human(file_size),rate)) def put(self, file_name): # 向服務端上傳文件 print('put') try: if not os.path.isfile(os.path.join(self.share_dir, file_name)): print('file:%s is not exists' % os.path.join(self.share_dir, file_name)) return else: file_size = os.path.getsize(os.path.join(self.share_dir, file_name)) header_dict = { 'file_name': file_name, 'md5': 'xxx', 'file_size': file_size } header_json = json.dumps(header_dict, ensure_ascii='False', indent=2) header_bytes = header_json.encode('utf-8') # 第二步:先發送報頭的長度 self.client.send(struct.pack('i', len(header_bytes))) # 第三步:再發報頭 self.client.send(header_bytes) # 第四步:再發送真實的數據 with open(os.path.join(self.share_dir, file_name), 'rb') as f: for line in f: self.client.send(line) except Exception as e: print(e) if __name__ == '__main__': c = TCPClient() c.run()
輸出結果:
sever: starting... from client ('127.0.0.1', 3500) send file 3.jpeg get file 1.pptx C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\server\share\1.pptx 總大小:970.93K 已上傳:%0.82 …… 總大小:970.93K 已上傳:%99.96 總大小:970.93K 已上傳:%100.00 client: C:/py3Project/路飛/第三模塊/第二章網絡編程/05_文件傳輸/簡單版本/client/file_client.py >> get 3.jpeg C:\py3Project\路飛\第三模塊\第二章網絡編程\05_文件傳輸\簡單版本\client\download\3.jpeg 總大小:75.36K 已下載:%10.62 …… 總大小:75.36K 已下載:%99.49 總大小:75.36K 已下載:%100.00 >> put 1.pptx put >>