zoukankan      html  css  js  c++  java
  • day27-1 粘包问题、解决粘包问题

    粘包问题

    • 只有TCP有粘包现象,UDP永远不会粘包

    socket收发消息的原理

    在TCP协议中,如服务端向客户端传输数据:发送端是两K两K的发送数据,接收端是一K一K的发送数据,发送端将多余的的数据放在缓存中,接收端在取的时候会取到两条数据的部分。造成粘包问题

    在UDP协议中,服务端向客户端传输数据:如发送端发送1025K的数据,而接收端只能接收1024K的数据,那多余的数据就会直接丢掉,下一条数据同理。所以UDP协议是不可靠传输,适用于传输小数据。不会有粘包问题

    所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

    TCP发送数据的四种情况

    假设客户端分别发送了两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4种情况。

    1. 服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包;
    2. 服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包;
    3. 服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包;
    4. 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1包的剩余内容D1_2和D2包的整包。

    粘包情况:两个数据非常小,然后间隔时间又短;数据太大,一次性取不完,下一次还会取这个大数据

    解决粘包问题

    解决粘包问题的原理:在传输数据之前,数据的大小必须得定长

    服务端

    import subprocess
    import struct
    from socket import *
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8000))
    server.listen(5)
    print('start...')
    
    # 连接循环
    while True:
        conn, client_addr = server.accept()
    
        # 通信循环
        while True:
            try:
                cmd = conn.recv(1024)
                print('来自客户端信息:', cmd)
    
                pipeline = subprocess.Popen(cmd.decode('utf8'),
                                            shell=True,
                                            stderr=subprocess.PIPE,
                                            stdout=subprocess.PIPE)
                stdout = pipeline.stdout.read()
                stderr = pipeline.stdout.read()
    
                byte_len = len(stdout) + len(stderr)
                guding_bytes = struct.pack('i', byte_len)
    
                conn.send(guding_bytes)
                conn.send(stdout+ stderr)
    
            except ConnectionResetError:
                break
    

    客户端

    import struct
    from socket import *
    
    client = socket(AF_INET, SOCK_STREAM)
    
    client.connect(('127.0.0.1', 8000))
    
    while True:
        cmd = input('please enter cmd>>>')
        client.send(cmd.encode('utf8'))
    
        guding_bytes = client.recv(4)
        data_len = struct.unpack('i', guding_bytes)[0]
    
        data = client.recv(data_len)
        print(data.decode('gbk'))
    

    为何TCP是可靠传输,UDP是不可靠传输

    • TCP在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据,所以TCP是可靠的
    • udp发送数据,对端是不会返回确认信息的,因此不可靠
  • 相关阅读:
    流程控制
    小结
    运算符
    进制之间的转换
    自动类型转换和强制类型转换
    变量
    关键字,标识符,
    NGINX 做TCP转发(端口转发)并记录日志
    redash安装
    解决 es CircuitBreakingException 问题(Data too large Error)
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11098956.html
Copyright © 2011-2022 走看看