原创博客>>>解决粘包问题的方法

原创博客>>>解决粘包问题的方法

  • 服务端:

    import socket
    import struct
    service=socket.socket()
    
    service.bind(('127.0.0.1',8081))
    while True:
        service.listen(5)
    
        conn,address=service.accept()
        print('有客户端连接进来了,地址如下',address)
        data_len_byte=conn.recv(4)
        # print(data_len_byte)
        data_len=struct.unpack('i',data_len_byte)[0]#把数据长度的字节码再转int
        data=conn.recv(data_len)
        print('我收到了客户端的数据',data)
        conn.send(b'ok')
  • 客户端

    import socket
    import struct
    client=socket.socket()
    client.connect(('127.0.0.1', 8081))
    
    msg=input('helloword,input>>>>')
    # print(msg.encode('utf8'))
    #把数据字节码的长度转为字节码  这个字节码固定是四位的
    msg_len_byte=struct.pack('i',len(msg.encode('utf8')))
    client.send(msg_len_byte)
    msg_byte=msg.encode('utf8')
    client.send(msg_byte)
    data=client.recv(4)
    print('来自服务端的信息',data)

    1740897-20190907173048350-1904890650.png

    以上的解决思路:客户端第一个send()往服务端发送固定长度为4 的字节码(客户端接下来要发送的真正内容的长度的字节码) ,然后服务端这边,第一个的recv(4)接收到这个数据的时候,就等于获取到了客户端接下来要发送的数据的字节码长度len,这个len作为接下来服务端接收的recv(len)的长度参数,客户端发送真正的数据的字节码后,服务端的recv(len)就完完整整的收到了真正的数据,一字不少不多。

    以上思路是针对于一种是粘在一起的包都是完整的数据包的粘包问题

    以下思路是针对于粘在一起的包有不完整的包。

    于是对以上的问题再次升级,代码放出

    • 服务端
    import socket
    import subprocess
    import struct
    soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    soc.bind(('127.0.0.1',8001))
    soc.listen(3)
    while True:
        print('等待客户端连接')
        conn,addr=soc.accept()
        print('有个客户端连接上了',addr)
        while True:
            try:
                data=conn.recv(1024)
                if len(data)==0:
                    break
                print(data)
                obj = subprocess.Popen(str(data,encoding='utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                #执行正确的结果 b 格式,gbk编码(windows平台)
                msg=obj.stdout.read()
    
                #发送的时候需要先把长度计算出来
                #头必须是固定长度
                #先发4位,头的长度
                import json
                dic={'size':len(msg)}
                dic_bytes=(json.dumps(dic)).encode('utf-8')
                #head_count是4个字节的长度
                head_count=struct.pack('i',len(dic_bytes))
                print(dic)
                conn.send(head_count)
                #发送头部内容
                conn.send(dic_bytes)
                #发了内容
                conn.send(msg)
            except Exception:
    
                break
        # 关闭通道
        conn.close()
    
    # 关闭套接字
    soc.close()
    • 客户端
    import socket
    import struct
    import json
    soc=socket.socket()
    
    soc.connect(('127.0.0.1',8001))
    while True:
        in_s=input('请输入要执行的命令:')
        soc.send(in_s.encode('utf-8'))
        #头部字典的长度
        head_dic_len=soc.recv(4)
        #解出真正的长度
        head_l=struct.unpack('i',head_dic_len)[0]
        #byte 字典的长度
        #收真正的头部字典
        dic_byte=soc.recv(head_l)
        head=json.loads(dic_byte)
        print(head)
        l=head['size']
        count=0
        data_total=b''
        print(l)
      #核心代码
        while count<l:
            if l<1024: #如果接受的数据小于1024 ,直接接受数据大小
                data=soc.recv(l)
            else:#如果接受的数据大于1024
                if l-count>=1024: #总数据长度-count(目前收到多少,count就是多少) 如果还大于1024  ,在收1024
                    data=soc.recv(1024)
                else: #总数据长度-count(目前收到多少,count就是多少) 如果小于1024,只收剩下的部分就可
                    data=soc.recv(l-count)
    
            data_total+=data
            count+=len(data)
    
        print(str(data_total,encoding='gbk'))

    思路:为了把粘在一起的包有不完整的包问题更加明显,特意找了subprocess模块,这个模块可以模拟cmd,输入tasklist命令的结果是很长的字节码,一般情况下recv(n)第一次只能打印前n个字节码,总之一次只能打印不完整的数据,必须多次打印接下来剩下的数据,于是就套用了while true,通过while true循环 拼接字节码 拼接整个数据的字节码,if判断读到的剩下数据是否到尾巴,到了尾巴将while 终止break,最后 将完整的数据的字节码打印出来。

转载于:https://www.cnblogs.com/demiao/p/11481992.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值