文件传输:
1.简单版本 服务端
1 import subprocess 2 import socket 3 import struct 4 import json 5 import os 6 7 share_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输简单版本servershare' # r 取消特殊符号的意思 应该写到配置文件中 8 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 9 phone.bind(('127.0.0.1',8080)) 10 phone.listen(5) 11 print('strating...') 12 while True: 13 conn,client_addr = phone.accept() 14 print(client_addr) 15 16 while True: 17 try: 18 # 1.收命令 19 res = conn.recv(8096) # b'get a.txt' 20 if not res:break 21 print('客户端数据:',res) 22 23 # 2.解析命令 提取相应的命令参数 24 cmds = res.decode('utf-8').split() 25 filename = cmds[1] 26 27 # 3.以读的方式打开文件,读取文件内容 发送给客户端 不知道文件的大小 还是用header_dic 28 # 第一步:制作固定长度的报头 # 将字典转成 str 转成 bytes 用到了序列化 29 header_dic = { 30 'filename':filename, 31 'md5':'xxxxxxx', 32 'file_size': os.path.getsize('%s/%s'%(share_dir,filename)) 33 } 34 header_json = json.dumps(header_dic) 35 header_bytes = header_json.encode('utf-8') # 这里不知道 多长 会粘包!! 36 37 # 第二步先发送报头的长度 38 conn.send(struct.pack('i',len(header_bytes))) 39 40 # 第三步:再发报头 41 conn.send(header_bytes) 42 43 # 第四部:在发真实的数据 44 with open('%s/%s'%(share_dir,filename),'rb') as f: 45 # conn.send(f.read()) 一下读出来 有可能文件 很大 46 for line in f: 47 conn.send(line) # 会粘包 连续好多个send 和一下发过去 一样的道理 但是节省内存 48 49 except ConnectionResetError: 50 break 51 conn.close() 52 53 phone.close()
1.简单版本 客户端
1 # -*- coding:utf-8 -*- 2 ''' 3 思路: 4 1.处理报头 准备发送的字典 先发报头的长度 再收报头 得到数据的长度 在收数据 5 做字典 能容纳 很多信息量 6 解决了:1.报头信息量少 2.i 格式有限的 解决了 7 ''' 8 import json 9 import socket 10 import struct 11 12 download_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输简单版本clientdownload' # 应该写到配置文件中 13 14 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 15 phone.connect(('127.0.0.1',8080)) 16 17 while True: 18 # 1.发命令 19 cmd = input('msg>>>:').strip() # get a.txt 软件自己定义的 格式 20 if not cmd:continue 21 phone.send(cmd.encode('utf-8')) 22 23 # 2.以写的方式打开一个新文件,接收服务端发来的文件内容写入客户的新文件 24 # 第一步 先收报头的长度 25 obj = phone.recv(4) 26 header_size = struct.unpack('i',obj)[0] 27 28 # 第二步:在收报头 29 header_bytes = phone.recv(header_size) 30 31 # 第三步:从报头中解析出对真实数据的描述 32 header_json = header_bytes.decode('utf-8') 33 header_dic = json.loads(header_json) 34 print(header_dic) 35 total_size = header_dic['file_size'] 36 filename = header_dic['filename'] 37 38 # 第四步:接收真实的数据 39 with open('%s/%s'%(download_dir,filename),'wb') as f: # filename wb 瞬间清掉 40 recv_size = 0 41 while recv_size < total_size: 42 line = phone.recv(1024) 43 f.write(line) 44 recv_size+=len(line) 45 print('总大小:%s 已下载:%s'%(total_size,recv_size)) # 这里应该有个进度条 提示用户 46 47 phone.close()
2.优化版本 服务端
1 import subprocess 2 import socket 3 import struct 4 import json 5 import os 6 7 share_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输优化版本servershare' # r 取消特殊符号的意思 应该写到配置文件中 8 9 10 def get(conn,cmds): 11 filename = cmds[1] 12 13 # 3.以读的方式打开文件,读取文件内容 发送给客户端 不知道文件的大小 还是用header_dic 14 # 第一步:制作固定长度的报头 # 将字典转成 str 转成 bytes 用到了序列化 15 header_dic = { 16 'filename': filename, 17 'md5': 'xxxxxxx', 18 'file_size': os.path.getsize('%s/%s' % (share_dir, filename)) 19 } 20 header_json = json.dumps(header_dic) 21 header_bytes = header_json.encode('utf-8') # 这里不知道 多长 会粘包!! 22 23 # 第二步先发送报头的长度 24 conn.send(struct.pack('i', len(header_bytes))) 25 26 # 第三步:再发报头 27 conn.send(header_bytes) 28 29 # 第四部:在发真实的数据 30 with open('%s/%s' % (share_dir, filename), 'rb') as f: 31 # conn.send(f.read()) 一下读出来 有可能文件 很大 32 for line in f: 33 conn.send(line) # 会粘包 连续好多个send 和一下发过去 一样的道理 但是节省内存 34 35 def put(): 36 pass 37 38 def run(): 39 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 40 phone.bind(('127.0.0.1',8080)) 41 phone.listen(5) 42 print('strating...') 43 while True: 44 conn,client_addr = phone.accept() 45 print(client_addr) 46 47 while True: 48 try: 49 # 1.收命令 50 res = conn.recv(8096) # b'get a.txt' 51 if not res:break 52 print('客户端数据:',res) 53 54 # 2.解析命令 提取相应的命令参数 55 cmds = res.decode('utf-8').split() 56 if cmds[0] == 'get': 57 get(conn,cmds) 58 elif cmds[0] == 'put': 59 put(conn,cmds) 60 61 62 except ConnectionResetError: 63 break 64 conn.close() 65 66 phone.close() 67 68 if __name__ == "__main__": 69 run()
2.优化版本 客户端
1 # -*- coding:utf-8 -*- 2 ''' 3 思路: 4 1.处理报头 准备发送的字典 先发报头的长度 再收报头 得到数据的长度 在收数据 5 做字典 能容纳 很多信息量 6 解决了:1.报头信息量少 2.i 格式有限的 解决了 7 ''' 8 import json 9 import socket 10 import struct 11 12 download_dir = r'D:路飞学城练习与作业pycharm练习6.网络编程5.文件传输优化版本clientdownload' # 应该写到配置文件中 13 14 def get(phone,cmds): 15 # 2.以写的方式打开一个新文件,接收服务端发来的文件内容写入客户的新文件 16 # 第一步 先收报头的长度 17 obj = phone.recv(4) 18 header_size = struct.unpack('i', obj)[0] 19 20 # 第二步:在收报头 21 header_bytes = phone.recv(header_size) 22 23 # 第三步:从报头中解析出对真实数据的描述 24 header_json = header_bytes.decode('utf-8') 25 header_dic = json.loads(header_json) 26 print(header_dic) 27 total_size = header_dic['file_size'] 28 filename = header_dic['filename'] 29 30 # 第四步:接收真实的数据 31 with open('%s/%s' % (download_dir, filename), 'wb') as f: # filename wb 瞬间清掉 32 recv_size = 0 33 while recv_size < total_size: 34 line = phone.recv(1024) 35 f.write(line) 36 recv_size += len(line) 37 print('总大小:%s 已下载:%s' % (total_size, recv_size)) # 这里应该有个进度条 提示用户 38 39 def put(phone,cmds): 40 pass 41 42 def run(): 43 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 44 phone.connect(('127.0.0.1',8080)) 45 46 while True: 47 # 1.发命令 48 inp = input('msg>>>:').strip() # get a.txt 软件自己定义的 格式 49 if not inp:continue 50 phone.send(inp.encode('utf-8')) 51 52 cmds = inp.split() 53 if cmds[0] == 'get': 54 get(phone,cmds) 55 elif cmds[0] == 'put': 56 put(phone,cmds) 57 58 phone.close() 59 60 if __name__ == "__main__": 61 run()
3.面向对象版本 服务端
1 import socket 2 import os 3 import struct 4 import pickle 5 6 7 class TCPServer: 8 address_family = socket.AF_INET 9 socket_type = socket.SOCK_STREAM 10 listen_count = 5 11 max_recv_bytes = 8192 12 coding = 'utf-8' 13 allow_reuse_address = False 14 # 下载的文件存放路径 15 down_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'share') 16 # 上传的文件存放路径 17 upload_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'upload') 18 19 def __init__(self,server_address,bind_and_listen=True): 20 self.server_address = server_address 21 self.socket = socket.socket(self.address_family,self.socket_type) 22 23 if bind_and_listen: 24 try: 25 self.server_bind() 26 self.server_listen() 27 except Exception: 28 self.server_close() 29 30 def server_bind(self): 31 if self.allow_reuse_address: 32 self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 33 self.socket.bind(self.server_address) 34 35 def server_listen(self): 36 self.socket.listen(self.listen_count) 37 38 def server_close(self): 39 self.socket.close() 40 41 def server_accept(self): 42 return self.socket.accept() 43 44 def conn_close(self,conn): 45 conn.close() 46 47 def run(self): 48 print('starting...') 49 while True: 50 self.conn,self.client_addr = self.server_accept() 51 print(self.client_addr) 52 while True: 53 try: 54 res = self.conn.recv(self.max_recv_bytes) 55 if not res:continue 56 cmds = res.decode(self.coding).split() 57 if hasattr(self,cmds[0]): 58 func = getattr(self,cmds[0]) 59 func(cmds) 60 except Exception: 61 break 62 self.conn_close(self.conn) 63 64 def get(self,cmds): 65 """ 下载 66 1.找到下载的文件 67 2.发送 header_size 68 3.发送 header_bytes file_size 69 4.读文件 rb 发送 send(line) 70 5.若文件不存在,发送0 client提示:文件不存在 71 :param cmds: 下载的文件 eg:['get','a.txt'] 72 :return: 73 """ 74 filename = cmds[1] 75 file_path = os.path.join(self.down_filepath, filename) 76 if os.path.isfile(file_path): 77 header = { 78 'filename': filename, 79 'md5': 'xxxxxx', 80 'file_size': os.path.getsize(file_path) 81 } 82 header_bytes = pickle.dumps(header) 83 self.conn.send(struct.pack('i', len(header_bytes))) 84 self.conn.send(header_bytes) 85 with open(file_path, 'rb') as f: 86 for line in f: 87 self.conn.send(line) 88 else: 89 self.conn.send(struct.pack('i', 0)) 90 91 def put(self,cmds): 92 """ 上传 93 1.接收4个bytes 得到文件的 header_size 94 2.根据 header_size 得到 header_bytes header_dic 95 3.根据 header_dic 得到 file_size 96 3.以写的形式 打开文件 f.write() 97 :param cmds: 下载的文件 eg:['put','a.txt'] 98 :return: 99 """ 100 obj = self.conn.recv(4) 101 header_size = struct.unpack('i', obj)[0] 102 header_bytes = self.conn.recv(header_size) 103 header_dic = pickle.loads(header_bytes) 104 print(header_dic) 105 file_size = header_dic['file_size'] 106 filename = header_dic['filename'] 107 108 with open('%s/%s' % (self.upload_filepath, filename), 'wb') as f: 109 recv_size = 0 110 while recv_size < file_size: 111 res = self.conn.recv(self.max_recv_bytes) 112 f.write(res) 113 recv_size += len(res) 114 115 116 tcp_server = TCPServer(('127.0.0.1',8080)) 117 tcp_server.run() 118 tcp_server.server_close()
3.面向对象版本 客户端
1 import socket 2 import struct 3 import pickle 4 import os 5 6 7 class FTPClient: 8 address_family = socket.AF_INET 9 socket_type = socket.SOCK_STREAM 10 # 下载的文件存放路径 11 down_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'download') 12 # 上传的文件存放路径 13 upload_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'share') 14 coding = 'utf-8' 15 max_recv_bytes = 8192 16 17 def __init__(self, server_address, connect=True): 18 self.server_address = server_address 19 self.socket = socket.socket(self.address_family, self.socket_type) 20 if connect: 21 try: 22 self.client_connect() 23 except Exception: 24 self.client_close() 25 26 def client_connect(self): 27 self.socket.connect(self.server_address) 28 29 def client_close(self): 30 self.socket.close() 31 32 def run(self): 33 while True: 34 # get a.txt 下载 put a.txt 上传 35 msg = input(">>>:").strip() 36 if not msg: continue 37 self.socket.send(msg.encode(self.coding)) 38 cmds = msg.split() 39 if hasattr(self,cmds[0]): 40 func = getattr(self,cmds[0]) 41 func(cmds) 42 43 def get(self, cmds): 44 """ 下载 45 1.得到 header_size 46 2.得到 header_types header_dic 47 3.得到 file_size file_name 48 4.以写的形式 打开文件 49 :param cmds: 下载的内容 eg: cmds = ['get','a.txt'] 50 :return: 51 """ 52 obj = self.socket.recv(4) 53 header_size = struct.unpack('i', obj)[0] 54 if header_size == 0: 55 print('文件不存在') 56 else: 57 header_types = self.socket.recv(header_size) 58 header_dic = pickle.loads(header_types) 59 print(header_dic) 60 file_size = header_dic['file_size'] 61 filename = header_dic['filename'] 62 63 with open('%s/%s' % (self.down_filepath, filename), 'wb') as f: 64 recv_size = 0 65 while recv_size < file_size: 66 res = self.socket.recv(self.max_recv_bytes) 67 f.write(res) 68 recv_size += len(res) 69 print('总大小:%s 已下载:%s' % (file_size, recv_size)) 70 else: 71 print('下载成功!') 72 73 def put(self, cmds): 74 """ 上传 75 1.查看上传的文件是否存在 76 2.上传文件 header_size 77 3.上传文件 header_bytes 78 4.以读的形式 打开文件 send(line) 79 :param cmds: 上传的内容 eg: cmds = ['put','a.txt'] 80 :return: 81 """ 82 filename = cmds[1] 83 file_path = os.path.join(self.upload_filepath, filename) 84 if os.path.isfile(file_path): 85 file_size = os.path.getsize(file_path) 86 header = { 87 'filename': os.path.basename(filename), 88 'md5': 'xxxxxx', 89 'file_size': file_size 90 } 91 header_bytes = pickle.dumps(header) 92 self.socket.send(struct.pack('i', len(header_bytes))) 93 self.socket.send(header_bytes) 94 95 with open(file_path, 'rb') as f: 96 send_bytes = b'' 97 for line in f: 98 self.socket.send(line) 99 send_bytes += line 100 print('总大小:%s 已上传:%s' % (file_size, len(send_bytes))) 101 else: 102 print('上传成功!') 103 else: 104 print('文件不存在') 105 106 107 ftp_client = FTPClient(('127.0.0.1',8080)) 108 ftp_client.run() 109 ftp_client.client_close()