Python-粘包、文件上传(ftp)
-
当多条信息发送时接受变成了一条或者出现接受不准确的情况
粘包现象会发生在发送端:
-
两条消息间隔时间短,长度短,就会把两条消息在发送之前就拼在一起
-
节省每一次发送消息回复的网络速度
-
多条消息发送到缓存端,但没有被即使接受,或者接受的长度不足一次发送的长度
-
数据与数据之间没有边界
本质:发送的每一条数据之间没有边界
struct
-
能够把一个任意大小的数据转换成固定的4个字节
import struct
ret = struct.pack('i', 1249519)
print(ret) # b'\xef\x10\x13\x00'
ret = struct.unpack('i', b'\xef\x10\x13\x00')
rett1 = struct.unpack('i', b'\xef\x10\x13\x00')[0]
print(ret) # (1249519,)
print(ret1) # 1249519
文件上传(ftp)
服务端:
import socket
import struct
import os
import json
import sys
REMOTE_DIR = os.path.join(os.path.dirname(_file_), 'remote')
def myrecv(conn):
num_bytes = conn.recv(4)
msg_len = struct.unpack('i', num_bytes)[0]
json_dic = conn.recv(msg_len).decode('utf-8')
opt_dic = json.loads(json_dic)
return opt_dic
def mysend(conn, dic):
dic_bytes = json.dumps(dic).encode('utf-8')
num_bytes = struct.pack('i', len(dic_bytes))
conn.send(num_bytes)
conn.send(dic_bytes)
def upload(conn):
filename = opt_dic['filename']
filesize = opt_dic['filesize']
filepath = os.path.join(REMOTE_DIR, filename)
with open(filepath, 'wb') as f:
while filesize > 0:
content = conn.recv(1024)
f.write(content)
filesize -= len(content)
# 要接受得字节数不一定是你实际接收到的数据长度
def download(conn):
filepath = os.path.join(REMOTE_DIR, opt_dic['filename'])
if os.path.isfile(filepath): # 判断是否存在这个文件
size = os.path.getsize(filepath) # 返回文件大小
dic = {'filesize': size}
mysend(conn, dic)
with open(filepath, 'rb') as f:
while szie > 0:
content = f.read(4096)
conn.send(content)
size -= len(content)
if __name__ = '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
conn, addr = accept()
opt_dic = myrecv(conn)
if hasattr(sys.modules[__name__], opt_dic['operate']):
getattr(sys.modules[__name__], opt_dic['operatee'])(conn)
客户端:
import socket
import os
import struct
import json
LOCAL_DIR = os.path.join(os.path.dirname(__file__), 'local')
def mysend(sk, opt_dic):
opt_bytes = json.dumps(opt_dic).encode('utf-8')
num_bytes = struct.pack('i', len(opt_bytes))
sk.send(num_bytes)
sk.send(opt_bytes)
def myrecv(sk):
bytes_len = sk.recv(4)
msg_len = struct.unpack('i', bytes_len)[0]
str_dic = sk.recv(msg_len).decode('utf-8')
size_dic = json.loads(str_dic)
return size_dic
def upload(sk):
path = input('请输入要上传的文件路径:') # 用户输入要上传的文件
if os.path.isfile(path): # 检查这个文件是否存在
filename = os.path.basename(path) # 获取文件名
filesize = os.path.getsize(path) # 获取文件大小
opt_dic = {'filename': filename, 'filesize': filesize, 'operate': 'upload'}
mysend(sk, opt_dic)
with open(path,'rb') as f:
while filesize > 0:
content = f.read(4096)
sk.send(content)
filesize -= len(content)
def download(sk):
# remote文件夹中的所有文件都可以下载
filename = input('请输入要下载的文件名:') # 用输入一个文件名
opt_dic = {'filename': filename, 'operate': 'download'}
mysend(sk, opt_dic)
size_dic = myrecv(sk)
filepath = os.path.join(LOCAL_DIR,filename)
with open(filepath, 'wb') as f:
while size_dic['filesize'] > 20:
content = sk.recv(1024)
f.write(content)
size_dic['filesize'] -= len(content)
if __name__ = '__main__':
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
opt_lst = [('上传', upload), ('下载', download)]
for index, opt in enumerate(opt_lst, 1):
print(index, opt)