zoukankan      html  css  js  c++  java
  • 粘包处理,文件传输

    粘包的概念
    粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估

    测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收

    缓冲区看,后一包数据的头紧接着前一包数据的尾。

    出现粘包的原因
    出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。

    发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。

    接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据

    粘包的处理方式:
    (1)当时短连接的情况下,不用考虑粘包的情况
    (2)如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
    (3)如果双方建立长连接,需要在连接后一段时间内发送不同结构数据

    接收方创建预处理线程,对接收到的数据包进行预处理,将粘连的包分开;

    分包是指在出现粘包的时候我们的接收方要进行分包处理。(在长连接中都会出现) 数据包的边界发生错位,导致读出错误的数据分包,进而曲解原始数据含义。

    粘包情况有两种,一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包。

    示例

    发送端

    import socket
    
    import struct
    ser=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    ser.bind(('127.0.0.1',10086))
    ser.listen(5)
    import subprocess
    while True:
        com,adr=ser.accept()
        while True:
            try:
                msg=com.recv(2048)
                if not msg:
                    com.close()
                    break
                cmd=msg.decode('utf-8')
                print('传入命令%s'%cmd)
                s= subprocess.Popen(cmd,stderr=subprocess.PIPE,
                                    stdout=subprocess.PIPE,shell=True)
                return_info=s.stdout.read()
                return_err=s.stderr.read()
                hander_size=len(return_info)+len(return_err)#使用struct 将真实数据的长度转为固定的字节数据
                print(hander_size)
                hander_bytes=struct.pack('i',hander_size)
            com.send(hander_bytes) #发送长度数据 com.send(return_err)#发送真实数据 com.send(return_info)
    except Exception as a: print(a) com.close() break

    接收端

    import socket
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect(('127.0.0.1',10086))
    import struct
    while True:
        cmd=input('请输入命令').strip()
        if not cmd:
            continue
        if cmd=='q':
            break
        client.send(cmd.encode('utf-8'))
        hander=client.recv(4)          #先收长度数据 字节数固定
        info_size=struct.unpack('i',hander)[0]
        print('接收到数据程度为%s'%info_size)
        info=client.recv(info_size)    #再收真实数据 真实可能很长 需要循环接收
        print(info.decode('gbk'))
    
    
    
    client.close()

    发送端和接收端必须都处理粘包 才算真正的解决了

  • 相关阅读:
    12迭代器
    11(2)Vector(向量)
    11(1) LinkList ---链表
    11集合(Collection<E>) Arraylist
    10异常
    乘法计算过程的模拟
    10 Date详解
    详细的OA系统学习
    8 math类
    Java开发中的23种设计模式详解
  • 原文地址:https://www.cnblogs.com/duGD/p/10946911.html
Copyright © 2011-2022 走看看