• 解决 TCP_socket 粘包问题




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


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

    解决方法:

    1、自定义字典类型 的数据报头{文件名:a,文件的size:1090}计算出该报头的长度(len(字节)),

    2、使用
    struct.pack('i',报头长度(一个数字))把一个数字压缩成固定的size 4个字节,发送给对端。

    3、对端 struct.unpack(‘i’,recv(4))接收固定大小4个字节;这就是接收到了 报头的长度。

    4.recv(报头长度)这就是发送过来的报头信息了






    import struct
    a='您好'
    a=len(a.encode('utf-8')) #字节的长度=====这个数据有多大字节
    # 1英文字母utf-8编码后=1字节
    # #1中文字符 utf-8编码后=3个字节
    #
    a=struct.pack('i',a) #struct.pack把数字转换成 固定大小 4个字节的 字节
    print(len(a)) #4个字节
    print(struct.unpack('i',a)[0]) #struct.unpack[0] 把成自己解包会数字




    服务端
    # import socket
    # import subprocess
    # iphon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #(建立一个socket对象)
    # iphon.bind(('127.0.0.1',8080))  #绑定到 IP+端口上 成为唯一的socket
    # iphon.listen(5)                   #设置连接池的个数
    # print('starting........')
    # while True:  #连接循环
    #     conn,addr=iphon.accept()  #等待电话连接
    #     print('电话线路是',conn)
    #     print('客户手机号:',addr)
    #     while True: #通信循环 发送和接收
    #         try:
    #             data=conn.recv(1024) #接受消息 最大从内存里接受1024MB数据
    #             print('客户端发来的消息是%s'%data)
    #             data=data.decode('utf-8') #从客户端发来的数据是经过编码的字节数据 所以需要解码 成Unicode
    #             res=subprocess.Popen( data, shell=True, stdout=subprocess.PIPE)  #解码后传进subprocess.Popen去cmd执行
    #             data1 = res.stdout.read().decode('gbk')      #cmd是gbk编码所以需要gbk解码
    #             print(data1)                                  #打印解码后的结果
    #             data1=data1.encode('gbk')                   #编码
    #             conn.send(data1)  #发送消息                  #编码后再传输给客户端
    #         except Exception:
    #             break
    #     conn.close()
    # iphon.close()
    
    import socket
    import struct
    import json
    phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    phon.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
    phon.bind(("127.0.0.1",8090)) 
    phon.listen(80)                 #
    while True:
        conn,addr=phon.accept()
        while True:
            try:
                data=conn.recv(4)      #接受4个字节的报头
                data=struct.unpack('i',data)[0]
                data1=conn.recv(data).decode('utf-8')  #接受 字节类型的报头信息
                                                        #{"file_name": "u4f60u597d", "file_size": 6}
                data1=json.loads(data1)
                print(data1)
                da=conn.recv(data1['file_size']).decode('utf-8') #接收真实数据
                print(da)
    
    
    
    
    
                # print("接受到来自客户端发来的消息",data)
                conn.send('sss'.encode('utf-8'))    #发送接受的消息 给某一个客户端
            except Exception:
                break
        conn.close()
    phon.close()
    

      










    客户端
    import socket
    import struct
    import json
    phon=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phon.connect(('127.0.0.1',8090))     #客户端的phon.connect正好对于服务端的phon1.accept()
    while True: #循环通信
        mes=input('---->: '.strip())
        if not mes:
            continue
        mes = mes.encode('utf-8')
        mes_len = len(mes)
        head = {'file_name': mes.decode('utf-8'), 'file_size': mes_len}
        head_json = json.dumps(head)  # {"file_name": "a", "file_size": 1}
        head_bytes = head_json.encode('utf-8')
        head_bytes_len = len(head_bytes)  # 51
        struct1 = struct.pack('i',head_bytes_len)
        send_=phon.send(struct1)  #发送4个字节的 报头长度
        data=phon.send(head_bytes) #发送报头
        da=phon.send(mes)          #发送真实数据
    
    
    phon.close()
  • 相关阅读:
    No necessary symbol fonts
    apt-get Error BrokenCount
    Repository XXX does not have a Realease file
    网页报错:You don't have permission to access
    Operating System not found
    JAVA平台AOP技术研究
    AOP技术基础
    SpringAOP浅析
    CGLIB动态代理
    Java设计模式—Proxy动态代理模式
  • 原文地址:https://www.cnblogs.com/sss4/p/6807515.html
Copyright © 2020-2023  润新知