文件传送
简单版
服务端
import socket import subprocess import struct import json import os share_dir = r'F:\project\book\chapter6\文件传输\简单版本\server\share' phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # (如果机器中存在,重新用端口)应对端口占用报错情况 phone.bind(("127.0.0.1", 9909)) # 127.0.0.1本地地址,端口范围0-65535:其中0-1024给操作系统使用 phone.listen(5) # 5代表最大挂起连接数 print("starting...") while True: # 循环链接 conn, client = phone.accept() # conn套接字对象 while True: # 通讯循环 try: # 1、接收命令 (命令:执行系统命令) res = conn.recv(8096) # b'get a.txt # 2、解析命令,提取相应的命令参数 cmds = res.decode("utf-8").split() filename = cmds[1] # 3、以读的方式打开文件,读取文件内容,发送给客户端 # 第一步:制作固定长度的报头(import struct) header_dic = { "filename": filename, "md5": "xxdxxx", "file_size": os.path.getsize(r"%s/%s" % (share_dir, filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode("utf-8") # 第二步:先发送报头的长度 conn.send(struct.pack("i", len(header_bytes))) # 第三步:再发报头 conn.send(header_bytes) # 第四步:再发送真实的数据 with open("%s/%s" % (share_dir, filename), "rb")as f: # conn.send(f.read()) # 如果文件太大,会占满内存 for line in f: conn.send(line) except ConnectionRefusedError: break conn.close() phone.close()
客户端
import socket import struct import json download_dir = r"F:\project\book\chapter6\文件传输\简单版本\client\download" phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) phone.connect(("127.0.0.1", 9909)) # phone相当于服务端的conn while True: # 1、发命令 cmd = input(">> ").strip() # get a.txt if not cmd: continue phone.send(cmd.encode("utf-8")) # 2、以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户端的新文件中 # 第一步:先收报头的长度 header = phone.recv(4) header_size = struct.unpack("i", header)[0] # 第二步:再接收报头信息 header_bytes = phone.recv(header_size) # 第三步:从报头中解析出对真实数据的描述信息 header_json = header_bytes.decode("utf-8") header_dic = json.loads(header_json) print(header_dic) file_size = header_dic["file_size"] filename = header_dic["filename"] # 第四步:接受真实的数据 with open("%s/%s" % (download_dir, filename), "wb")as f: recv_size = 0 while recv_size < file_size: line = phone.recv(1024) f.write(line) recv_size += len(line) print("总大小:%s 已下载大小:%s" % (file_size, recv_size)) phone.close()
函数版
服务端
import socket import subprocess import struct import json import os share_dir = r'F:\project\book\chapter6\文件传输\函数版本\server\share' def get(conn, cmds): filename = cmds[1] # 3、以读的方式打开文件,读取文件内容,发送给客户端 # 第一步:制作固定长度的报头(import struct) header_dic = { "filename": filename, "md5": "xxdxxx", "file_size": os.path.getsize(r"%s/%s" % (share_dir, filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode("utf-8") # 第二步:先发送报头的长度 conn.send(struct.pack("i", len(header_bytes))) # 第三步:再发报头 conn.send(header_bytes) # 第四步:再发送真实的数据 with open("%s/%s" % (share_dir, filename), "rb")as f: # conn.send(f.read()) # 如果文件太大,会占满内存 for line in f: conn.send(line) def put(conn, cmds): pass def run(): phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # (如果机器中存在,重新用端口)应对端口占用报错情况 phone.bind(("127.0.0.1", 9909)) # 127.0.0.1本地地址,端口范围0-65535:其中0-1024给操作系统使用 phone.listen(5) # 5代表最大挂起连接数 print("starting...") while True: # 循环链接 conn, client = phone.accept() # conn套接字对象 while True: # 通讯循环 try: # 1、接收命令 (命令:执行系统命令) res = conn.recv(8096) # b'get a.txt # 2、解析命令,提取相应的命令参数 cmds = res.decode("utf-8").split() if cmds[0] == "get": get(conn, cmds) elif cmds[0] == "put": put(conn, cmds) except ConnectionRefusedError: break conn.close() phone.close() if __name__ == "__main__": #如果是执行当前文件的时候,这个条件成立,就执行。如果当前文件被其他文件当成模块导入的时候,这个条件是不成立的,里面的代码是不执行的 run()
客户端
import socket import struct import json download_dir = r"F:\project\book\chapter6\文件传输\函数版本\client\download" def get(phone, cmds): # 2、以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户端的新文件中 # 第一步:先收报头的长度 header = phone.recv(4) header_size = struct.unpack("i", header)[0] # 第二步:再接收报头信息 header_bytes = phone.recv(header_size) # 第三步:从报头中解析出对真实数据的描述信息 header_json = header_bytes.decode("utf-8") header_dic = json.loads(header_json) print(header_dic) file_size = header_dic["file_size"] filename = header_dic["filename"] # 第四步:接受真实的数据 with open("%s/%s" % (download_dir, filename), "wb")as f: recv_size = 0 while recv_size < file_size: line = phone.recv(1024) f.write(line) recv_size += len(line) print("总大小:%s 已下载大小:%s" % (file_size, recv_size)) def put(phone, cmds): pass def run(): phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) phone.connect(("127.0.0.1", 9909)) # phone相当于服务端的conn while True: # 1、发命令 inp = input(">> ").strip() # get a.txt if not inp: continue phone.send(inp.encode("utf-8")) cmds = inp.split() # ["get","a.txt"] if cmds[0] == "get": get(phone, cmds) elif cmds[0] == "put": put(phone, cmds) phone.close() if __name__ == "__main__": # 如果是执行当前文件的时候,这个条件成立,就执行。如果当前文件被其他文件当成模块导入的时候,这个条件是不成立的,里面的代码是不执行的 run()
类版本
服务端
import socket import subprocess import struct import json import os # 面相对象的好处可以把数据和操作数据的方法整合到一起 class MYServer: address_family = socket.AF_INET socket_type = socket.SOCK_STREAM max_packet_size = 8192 coding = "utf-8" request_queue_size = 5 allow_reuse_address = False # 允许地址再用 server_dir = r"F:\project\book\chapter6\文件传输\函数版本\server\share" def __init__(self, server_address, bind_and_activate=True): self.server_address = server_address self.socket = socket.socket(self.address_family, self.socket_type) if bind_and_activate: ####### try: self.server_bind() self.server_activate() except EOFError: self.server_close() raise def server_bind(self): if self.allow_reuse_address: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address) # self.server_address = self.socket.getsockname() # 本机的IP和端口号 def server_activate(self): self.socket.listen(self.request_queue_size) def server_close(self): self.socket.close() def get_request(self): return self.socket.accept() def close_request(self, request): request.close() def run(self): while True: # 循环链接 self.conn, self.client_addr = self.get_request() # conn套接字对象 print("from client", self.client_addr) while True: # 通讯循环 try: head_struct = self.conn.recv(4) if not head_struct: break head_len = struct.unpack('i', head_struct)[0] # 返回的客户端传送数据的长度 head_json = self.conn.recv(head_len).decode(self.coding) # path head_dic = json.loads(head_json) print(head_dic) # head_dic={'cmd':'put','filename':'a.txt','filesize':123123} cmd = head_dic['cmd'] if hasattr(self, cmd): func = getattr(self, cmd) func(head_dic) except ConnectionRefusedError: break def put(self, args): file_path = os.path.normpath(os.path.join(self.server_dir, args['filename'])) # 规范化路径。 filesize = args['filesize'] recv_size = 0 print('----->', file_path) with open(file_path, 'wb') as f: while recv_size < filesize: recv_data = self.conn.recv(self.max_packet_size) f.write(recv_data) recv_size += len(recv_data) print('recvsize:%s filesize:%s' % (recv_size, filesize)) def get(self, args): # 下载 cmd = args[0] filename = args[1] if not os.path.isfile(filename): print('file:%s is not exists' % filename) return else: filesize = os.path.getsize(filename) head_dic = {'cmd': cmd, 'filename': os.path.basename(filename), 'filesize': filesize} print(head_dic) head_json = json.dumps(head_dic) head_json_bytes = bytes(head_json, encoding=self.coding) head_struct = struct.pack('i', len(head_json_bytes)) self.socket.send(head_struct) self.socket.send(head_json_bytes) send_size = 0 with open(filename, 'rb') as f: for line in f: self.socket.send(line) send_size += len(line) print(send_size) server = MYServer(('127.0.0.1', 8080)) server.run()
客户端
import socket import struct import json import os class MYClient: address_family = socket.AF_INET socket_type = socket.SOCK_STREAM allow_reuse_address = False max_packet_size = 8192 coding = 'utf-8' request_queue_size = 5 def __init__(self, server_address, connect=True): self.server_address = server_address self.socket = socket.socket(self.address_family, self.socket_type) if connect: try: self.client_connect() except EOFError: self.client_close() raise def client_connect(self): self.socket.connect(self.server_address) def client_close(self): self.socket.close() def run(self): while True: inp = input(">>: ").strip() if not inp: continue l = inp.split() cmd = l[0] if hasattr(self, cmd): func = getattr(self, cmd) func(l) def put(self, args): # 上传 cmd = args[0] filename = args[1] if not os.path.isfile(filename): print('file:%s is not exists' % filename) return else: filesize = os.path.getsize(filename) head_dic = {'cmd': cmd, 'filename': os.path.basename(filename), 'filesize': filesize} print(head_dic) head_json = json.dumps(head_dic) head_json_bytes = bytes(head_json, encoding=self.coding) head_struct = struct.pack('i', len(head_json_bytes)) self.socket.send(head_struct) self.socket.send(head_json_bytes) send_size = 0 with open(filename, 'rb') as f: for line in f: self.socket.send(line) send_size += len(line) print(send_size) else: print('upload successful') def get(self, args): # 下载 file_path = os.path.normpath(os.path.join(self.server_dir, args['filename'])) # 规范化路径。 filesize = args['filesize'] recv_size = 0 print('----->', file_path) with open(file_path, 'wb') as f: while recv_size < filesize: recv_data = self.conn.recv(self.max_packet_size) f.write(recv_data) recv_size += len(recv_data) print('recvsize:%s filesize:%s' % (recv_size, filesize)) else: print('download successful') client = MYClient(('127.0.0.1', 8080)) client.run()