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)
   inp = int(input('>>>'))
   opt_lst[inp-1][1](sk)

 

 

 

 

 

 

 

 

posted on 2020-03-06 11:32  we我们  阅读(416)  评论(0)    收藏  举报