zoukankan      html  css  js  c++  java
  • 网络编程之黏包现象

    <关于python黏包现象的那些事>

    1.黏包

    1.1  什么是黏包?

    同时执行多条命令后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现是黏包。

    注释:黏包只会发生在tcp协议中,这后边会将原因。

    1.2  黏包成因

    • 关于tcp:基于tcp的套接字客户端往服务端上传文件,发送文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流是从何处可似乎的,从何处结束。此外发送端引起的黏包是由tcp协议本身造成的,tcp为提高传输效率,发送方往往要收集到足够多的数据后才发送一个tcp段。若连续几次需要send数据很少,会根据优化算法合并到一段一次发,这样形成一次发。
    • 关于udp不会发生黏包:是无链接的,面向消息的,提高效率服务,不会使用块的合并优化算法,由于ydp支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的udp包,在每个udp包都有了消息头(消息来源地址,端口信息),这样很容易区分。即有消息保护边界。

    1.3  发生黏包的两种情况

    1    发送方的缓存机制:发送端需要等缓冲区满才发送出去,造成黏包(发送数据时间间隔很短,数据很小会合到一起,产生黏包)

    2    接收方的缓存机制:接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只接收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生黏包)

    总结:   表面上:黏包问题主要是因为发送方和接收方的缓存机制,tcp协议面向流通信的特点。

        实际上:主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的。

    1.4  黏包的解决方案

    解决方案1

    如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收方知晓,然后来一个死循环接收完所有数据。

    import struct
    import socket 
    sk=socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    conn,addr=sk.accept()
    while True:
        s=input(/>>>/).encode('utf-8')
        pack_num=struct.pack('i',len(s))
        conn.send(pack_num)
        conn.send(s)
    conn.close()
    sk.close()
    import socket
    import struct
    sk=socket.socket()
    sk.connect(('127.0.0.1',9000))
    while True:
        pack_num=sk.recv(4)
        num=struct.unpack('i',pack_num)[0]
        ret=sk.recv(num)
        print(ret.decode('utf-8'))
    sk.close()
    

      

    解决方案进阶

    stuct模块

    该模块可以把一个类型,如数字转成固定长度的bytes

    >>> struct.pack('i',1111111111111)
    
    struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围

  • 相关阅读:
    sqlalchemy 使用pymysql连接mysql 1366错误
    mysql之数据导出
    Go常见语句
    huffman code
    后缀数组,目前比较赶进度,而且有点难,所以放到以后再来看
    hash
    bipartite matching
    spanning tree
    拓扑排序
    Union Find
  • 原文地址:https://www.cnblogs.com/13507215809qwer-/p/9658218.html
Copyright © 2011-2022 走看看