1、通过socket收发文件(基于TCP协议)
1.1、上传文件(在同一ip下进行)
settings:
import os,sys BASE_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.append(BASE_DIR) path_db = os.path.dirname(os.path.abspath(__file__)) path_server = os.path.join(path_db,'server') path_client = os.path.join(path_db,'client')
客户端:
import socket import struct import json import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings def run(): phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',9900)) while True: # 1、发命令 cmd = input('>>: ').strip() # get 3.jpeg if not cmd: continue cmds = cmd.split() filename = cmds[1] try: header_dic = { 'filename': filename, 'md5': 'xxdxxx', 'file_size': os.path.getsize(os.path.join(settings.path_client, filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') phone.send(struct.pack('i', len(header_bytes))) # len(header_bytes)发送信息给客户端的字节长度 phone.send(header_bytes) # 客户端发两次 with open(os.path.join(settings.path_client, filename), 'rb') as f: for line in f: phone.send(line) except ConnectionResetError: # 适用于windows操作系统 break phone.close() if __name__ == '__main__': run()
服务端:
import socket import subprocess import struct import json # ------------------------上传功能和下载功能的逻辑对换一下就可以------------------------------------------------------ import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',9900)) #0-65535:0-1024给操作系统使用 phone.listen(5) print('starting...') while True: # 链接循环 conn,client_addr=phone.accept() print(client_addr) while True: try: obj = conn.recv(4) # 接收服务端传来的 struct.pack('i',len(header_bytes)) header_size = struct.unpack('i', obj)[0] # 解包--得到服务端传给客户端 header_dic字典字节的长度 # 第二步:再收报头 header_bytes = conn.recv(header_size) # header_size为上一步已经算好的字典字节长度 # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据 # 第三步:从报头中解析出对真实数据的描述信息 header_json = header_bytes.decode('utf-8') # class---> str类型 header_dic = json.loads(header_json) # 反序列化 服务端原先的 字典 print(header_dic) total_size = header_dic['file_size'] # 服务端的执行后返回给客户端的字节流长度 # 第四步:接收真实的数据 filename = header_dic['filename'] with open(os.path.join(settings.path_server, filename), 'wb') as f: recv_size = 0 while recv_size < total_size: line = conn.recv(1024) # 1024是一个坑 f.write(line) recv_size += len(line) print(f'总大小{total_size},已下载{recv_size}') except ConnectionResetError: break conn.close() phone.close()
1.2、下载文件
客户端:
import socket import struct import json import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',9909)) while True: #1、发命令 cmd=input('>>: ').strip() # get 3.jpeg if not cmd:continue phone.send(cmd.encode('utf-8')) #2、以写的方式打开一个新文件,接收服务端发来的文件内容写入客户端的新文件 #第一步:先收报头的长度 obj=phone.recv(4) #接收服务端传来的 struct.pack('i',len(header_bytes)) header_size=struct.unpack('i',obj)[0] # 解包--得到服务端传给客户端 header_dic字典字节的长度 #第二步:再收报头 header_bytes=phone.recv(header_size) # header_size为上一步已经算好的字典字节长度 # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据 #第三步:从报头中解析出对真实数据的描述信息 header_json=header_bytes.decode('utf-8') # class---> str类型 header_dic=json.loads(header_json) # 反序列化 服务端原先的 字典 print(header_dic) total_size=header_dic['file_size'] # 服务端的执行后返回给客户端的字节流长度 #第四步:接收真实的数据 filename = header_dic['filename'] with open(os.path.join(settings.path_client,filename),'wb') as f: recv_size=0 while recv_size < total_size: line=phone.recv(1024) #1024是一个坑 f.write(line) recv_size+=len(line) print(f'总大小{total_size},已下载{recv_size}') # print(recv_data.decode('gbk')) phone.close()
服务端:
import socket import subprocess import struct import json import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings 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)) #0-65535:0-1024给操作系统使用 phone.listen(5) print('starting...') while True: # 链接循环 conn,client_addr=phone.accept() print(client_addr) while True: #通信循环 try: #1、收命令 res=conn.recv(8096) # b'get 3.jpeg' if not res:break #适用于linux操作系统 #2、解析命令,提取相应的命令参数 cmds = res.decode('utf-8').split() filename = cmds[1] #3、以读取方式打开文件,读取文件内容 发给客户端 #第一步:制作固定长度的报头 header_dic={ 'filename':filename, 'md5':'xxdxxx', 'file_size': os.path.getsize(os.path.join(settings.path_server,filename)) } header_json=json.dumps(header_dic) header_bytes=header_json.encode('utf-8') #第二步:先发送报头的长度 conn.send(struct.pack('i',len(header_bytes))) # len(header_bytes)发送信息给客户端的字节长度 #第三步:再发报头 conn.send(header_bytes) # 客户端发两次 with open(os.path.join(settings.path_server,filename),'rb') as f: for line in f: conn.send(line) #第四步:再发送真实的数据 except ConnectionResetError: #适用于windows操作系统 break conn.close() phone.close()
2、上传、下载代码优化(函数版本)
客户端:
import socket import struct import json import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings def get(phone): obj = phone.recv(4) # 接收服务端传来的 struct.pack('i',len(header_bytes)) header_size = struct.unpack('i', obj)[0] # 解包--得到服务端传给客户端 header_dic字典字节的长度 header_bytes = phone.recv(header_size) # header_size为上一步已经算好的字典字节长度 # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据 # 第三步:从报头中解析出对真实数据的描述信息 header_json = header_bytes.decode('utf-8') # class---> str类型 header_dic = json.loads(header_json) # 反序列化 服务端原先的 字典 print(header_dic) total_size = header_dic['file_size'] # 服务端的执行后返回给客户端的字节流长度 # 第四步:接收真实的数据 filename = header_dic['filename'] with open(os.path.join(settings.path_client, filename), 'wb') as f: recv_size = 0 while recv_size < total_size: line = phone.recv(1024) # 1024是一个坑 f.write(line) recv_size += len(line) print(f'总大小{total_size},已下载{recv_size}') def put(phone,cmds): filename = cmds[1] # try: header_dic = { 'filename': filename, 'md5': 'xxdxxx', 'file_size': os.path.getsize(os.path.join(settings.path_client, filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') phone.send(struct.pack('i', len(header_bytes))) # len(header_bytes)发送信息给客户端的字节长度 phone.send(header_bytes) # 客户端发两次 with open(os.path.join(settings.path_client, filename), 'rb') as f: for line in f: phone.send(line) def run(): phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',9909)) while True: #1、发命令 cmd=input('>>: ').strip() # get 3.jpeg if not cmd:continue phone.send(cmd.encode('utf-8')) cmds = cmd.split() if cmds[0] == 'get': get(phone) if cmds[0] == 'put': try: put(phone,cmds) except ConnectionResetError: # 适用于windows操作系统 break phone.close() if __name__ == '__main__': run()
服务端:
import socket import subprocess import struct import json import os,sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from db import settings def get(conn,cmds): filename = cmds[1] header_dic = { 'filename': filename, 'md5': 'xxdxxx', 'file_size': os.path.getsize(os.path.join(settings.path_server, filename)) } header_json = json.dumps(header_dic) header_bytes = header_json.encode('utf-8') # 第二步:先发送报头的长度 conn.send(struct.pack('i', len(header_bytes))) # len(header_bytes)发送信息给客户端的字节长度 # 第三步:再发报头 conn.send(header_bytes) # 客户端发两次 with open(os.path.join(settings.path_server, filename), 'rb') as f: for line in f: conn.send(line) def put(conn): obj = conn.recv(4) # 接收服务端传来的 struct.pack('i',len(header_bytes)) header_size = struct.unpack('i', obj)[0] # 解包--得到服务端传给客户端 header_dic字典字节的长度 # 第二步:再收报头 header_bytes = conn.recv(header_size) # header_size为上一步已经算好的字典字节长度 # header_bytes 为 接收客户端第二次发过来的header_dic字典转化的成的字节数据 # 第三步:从报头中解析出对真实数据的描述信息 header_json = header_bytes.decode('utf-8') # class---> str类型 header_dic = json.loads(header_json) # 反序列化 服务端原先的 字典 print(header_dic) total_size = header_dic['file_size'] # 服务端的执行后返回给客户端的字节流长度 # 第四步:接收真实的数据 filename = header_dic['filename'] with open(os.path.join(settings.path_server, filename), 'wb') as f: recv_size = 0 while recv_size < total_size: line = conn.recv(1024) # 1024是一个坑 f.write(line) recv_size += len(line) print(f'总大小{total_size},已下载{recv_size}') 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)) #0-65535:0-1024给操作系统使用 phone.listen(5) print('starting...') while True: # 链接循环 conn,client_addr=phone.accept() print(client_addr) while True: #通信循环 try: #1、收命令 res=conn.recv(8096) # b'get 3.jpeg' if not res:break #2、解析命令,提取相应的命令参数 cmds = res.decode('utf-8').split() if cmds[0] == 'get': get(conn,cmds) if cmds[0] == 'put': put(conn) except ConnectionResetError: #适用于windows操作系统 break conn.close() phone.close() if __name__ == '__main__': run()