• python之socket编程------粘包


    一、粘包

    什么是粘包

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

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

    两种情况发生粘包:

    1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时时间间隔短,数据很小,会合在一起,产生粘包)

    from socket import *
    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    conn,client_addr=phone.accept()
    
    
    data1=conn.recv(1024)
    print('data1: ',data1)
    data2=conn.recv(1024)
    print('data2:',data2)
    服务端
    from socket import *
    import time
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8080))
    
    phone.send('hello'.encode('utf-8'))
    # time.sleep(5)
    phone.send('world'.encode('utf-8'))
    客户端

    2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送一段数据,服务端之接收了一小部分,服务端下次在接受的时候还是

         从缓冲区拿上上次遗留的数据,产生粘包)

    from socket import *
    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    conn,client_addr=phone.accept()
    
    
    
    
    data1=conn.recv(10)
    print('data1: ',data1)
    data2=conn.recv(4)
    print('data2:',data2)
    服务端
    from socket import *
    import time
    phone=socket(AF_INET,SOCK_STREAM)
    phone.connect(('127.0.0.1',8080))
    
    
    
    phone.send('helloworld'.encode('utf-8'))
    phone.send('egon'.encode('utf-8'))
    客户端

    二、解决粘包问题

    struct模块

    import struct
    res=struct.pack('i',111112)
    print(res,len(res),type(res))
    unpack_res=struct.unpack('i',res)
    print(unpack_res[0])
    struct模块

    struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围

    import socket
    import struct
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    phone.connect(('127.0.0.1',8082)) #绑定手机卡
    
    #发,收消息
    while True:
        cmd=input('>>: ').strip()
        if not cmd:continue
    
        phone.send(cmd.encode('utf-8'))
        #先收报头
        header_struct=phone.recv(4)
        unpack_res = struct.unpack('i', header_struct)
        total_size=unpack_res[0]
    
        #再收数据
        recv_size=0 #10241=10240+1
        total_data=b''
        while recv_size < total_size:
            recv_data=phone.recv(1024)
            recv_size+=len(recv_data)
            total_data+=recv_data
        print(total_data.decode('gbk'))
    phone.close()
    客户端
    import socket
    import subprocess
    import struct
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
    phone.bind(('127.0.0.1',8082)) #绑定手机卡
    phone.listen(5) #开机
    
    print('starting...')
    while True: #链接循环
        conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
        print('-------->',conn,client_addr)
    
        #收,发消息
        while True:#通信循环
            try:
                cmd=conn.recv(1024)
                if not cmd:break #针对linux
                #执行cmd命令,拿到cmd的结果,结果应该是bytes类型
                #。。。。
                res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)
                stdout=res.stdout.read()
                stderr=res.stderr.read()
    
                #先发报头(转成固定长度的bytes类型)
                header = struct.pack('i',len(stdout)+len(stderr))
                conn.send(header)
                #再发送命令的结果
                conn.send(stdout)
                conn.send(stderr)
            except Exception:
                break
        conn.close() #挂电话
    phone.close() #关机
    服务端
  • 相关阅读:
    MySQL百万级数据量分页查询方法及其优化
    Windows10内置Linux子系统初体验
    谈谈区块链(18):以太坊的UTXO
    永久告别mac屏幕涂层脱落
    Cloud Foundry中DEA启动应用实例时环境变量的使用
    jQuery 事件方法大全-超全的总结
    UVA12304-2D Geometry 110 in 1!
    Hbase总结(五)-hbase常识及habse适合什么场景
    Android笔记之 网络http通信
    Mac下安装Redis
  • 原文地址:https://www.cnblogs.com/mengqingjian/p/7412106.html
Copyright © 2020-2023  润新知