-
当多条信息发送时接受变成了一条或者出现接受不准确的情况
粘包现象会发生在发送端:
-
两条消息间隔时间短,长度短,就会把两条消息在发送之前就拼在一起
-
节省每一次发送消息回复的网络速度
-
多条消息发送到缓存端,但没有被即使接受,或者接受的长度不足一次发送的长度
-
数据与数据之间没有边界
本质:发送的每一条数据之间没有边界
struct
-
能够把一个任意大小的数据转换成固定的4个字节
import structret = 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 socketimport structimport osimport jsonimport sysREMOTE_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_dicdef 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 socketimport osimport structimport jsonLOCAL_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_dicdef 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) inp = int(input('>>>')) opt_lst[inp-1][1](sk)
来源:https://www.cnblogs.com/womenzt/p/12425599.html