zoukankan      html  css  js  c++  java
  • 基于socket 数据传输的粘包问题

    首先为什么存在粘包?
    1.点连续较小的seed (Nagle算法会进行打包发送)那么就会粘包
    2.当发送的数据大于接收的限制也就是发送的seed'>接收的recv字节的数量时,一次接受不完,那么当第二次输入指令的时候就会发生取的是第一次没取完的数据,一直到取完第一次的数据,这也称之为粘包
    在解决粘包之前,我们介绍一个概念缓冲区:
    什么是缓冲区:?
    .在我们接收和发送时接收和发送是存在缓存区的那么他们的作用是什么,
    缓存区的作用:
    1.暂时储存一些数据
    2.1. 缓冲区如果你的网络波动,保证数据的收发稳定,匀速但是:也就造成了粘包现象之一:当出现连续的seed多次数据(微小的数据)时,你的数据会粘在一起发送出去(底层缘由是Nagle算法:将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。)上图

    这就是缓冲区!!!!!
    那么怎样解决粘包:
    思路提供:1. 设服务端发送10000字节

    1. 客户端收数据的时候循环接收,(1024)例每次接收1024个字节,直至将所有的字节接收完毕最后一起解码

    2. 遇到问题

      1.recv 的次数无法确定

      2.你发送的总数据之前先给我发个总的数据长度例:1000字节,然后在发送总数据

      3.客户端:先接受一个长度,10000字节然后我再循环只要你接收的数据小于10000字节我就一直接收
      4.问题二:总数据长度不固定

    3. 你要将total_size int类型转化成bytes类型才可以发送

      387 ---- > str(387) '387' ---->bytes b'387' 长度 3bytes

      4185 ----> str(4185) '4185' ---->bytes b'4185' 长度 4bytes

      18000------------------------------------------------------> 长度 5bytes

      我们要解决:

      将不固定长度的int类型转化成固定长度的bytes并且还可以翻转回来。

      struct模块

    那么我们就可以解决粘包:这是一个low版

    import socket
    import struct
    import subprocess
    phone = socket.socket()
    phone.bind(('127.0.01',8878))
    Python.listen(5)
    while 1:
        conn,adds = phone.accept()
        while 1:
            try:
                receives_commands = conn.recv(1024)
                receives_commands = receives_commands.decode('utf-8')
                if receives_commands = 'Q':break
                obj = subprocess.Popen(receives_commands,
                                      shall = True
                                      stdout = subprocess.PIPE
                                      stderr =subprocess.PIPE )
                ret = obj.stdout.read()+obj.stderr.read()
                ret = ret.encode('utf-8')
                ret_len = len(ret)
                ret_len_struct = struct.pack('i',ret_len) 
                conn.send(ret_len_struct)
                conn.send(ret)
           except ConnectionResetError:
           		print('客户端终端')
                break
           conn.cloce()
    phone.cloce()
    #客户端
    import socket 
    import struct
    while 1:
        dispatch_orders = inport('请输入您的命令:').strip().encode('utf-8')
        if not dispatch_orders:print('不为空')
        phone.send(dispatch_orders)
        if dispatch_orders.upper() == b'Q':break
        receives_commands_hand = phone.recv(4)
        receives_commands_hand = struct.unpack('i',receives_commands_hand)
        tata =b'' 
        while len(tata)<receives_commands_hand:
            tata+=phone.recv(1024)
        tata = tata.decode('gbk')
        print(f'来自服务端的回执 
     {tata}')
    phone.close()
       
    

    这样我们就解决了一部份粘包问题,那么有low版,也就有高大上版本,那么在这里给大家提供下思路:

    1. 我们要制作固定的报头
    2. 你现在有两段不固定长度的bytes类型,我们要固定报头,所以
      1. 你获取不固定长度的报头
      2. 利用struct 模块将不固定长度的报头固定成四个字节
      3. 先发送4字节再发送包头
      4. 先发送报头,再发总数据(有三部传输数据的过程(1.先发报头的长度,2.再发报头,3再发总文件数据))
  • 相关阅读:
    添加脚本真机调试Error launching remote program: failed to get the task for process xxx.
    问题资源Android lint 能够做的事情
    调用生成通过存储过程自动生成AWR报告
    破解行Android apk 逆向工程研究﹣破解 MyTV HD 機種限制手記
    代码判断判断给定的图是否是有向无环图
    修改系统android2.3.4增加gsensor
    类对象工厂设计模式(Factory Pattern)
    脚本指令《游戏脚本的设计与开发》第一章 读取和解析一个脚本文件
    级别指示Android Hierarchy 工具的一些知识
    nullnull[小代码] 双击BACK键 退出
  • 原文地址:https://www.cnblogs.com/wuzifan/p/11420926.html
Copyright © 2011-2022 走看看