zoukankan      html  css  js  c++  java
  • Day29--Python--缓冲区, 粘包

    tcp: 属于长连接,与一个客户端进行连接了以后,其他的客户端要等待.要想连接另外一个客户端,需要优雅地断开当前客户端的连接

    允许地址重用:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    在bind IP地址和端口之前,写这句话,防止端口被占用无法使用.


    缓冲区:
    输入缓冲区 # recv
    输出缓冲区 # send

    什么是缓冲区,为什么会有缓冲区?
    缓冲区: 暂时存放传输数据的地方.
    每个socket对象被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区. 当发送消息的时候,
    先将数据写入输出缓冲区中,再由TCP/UDP协议将数据从缓冲区发送到目标机器. 一旦数据写入到缓冲区,
    无论是否发送到目标机器,程序都可以执行下一步操作,这样可以防止网络不畅通造成的程序阻塞.
    当接收数据的时候,会从输入缓冲区中读取数据,而不是直接从网络中读取,这样cpu可以处理完当前任务后从输入缓冲区读取信息.

    参考: 缓冲区与缓存
    MTU:最大传输单元(Maximum Transmission Unit)
      网络层限制是1518b,每次发送数据的时候最好不要超过这个数


    粘包(tcp的两种粘包现象)
    1. 连续发送小的数据,并且每次发送之间的时间间隔很短. (两个消息在输出缓冲区粘连到一起)
    原因是tcp为了传输效率,做了一个优化算法(Nagle),减少连续的小包发送.因为每一个消息被包裹以后都会有两个过程:
    1. 组包 2. 拆包0, 会降低效率
    2. 第一次服务端发送的数据比客户端设置的一次接收消息的size要大, 一次接收不完,第二次接收的时候就会把第一次剩余的消息接收到.

    粘包的根本原因: 双方不知道对方发送消息的大小.
    解决方案1:
    发送消息之前,先计算要发送消息的长度,然后先将消息长度发送过去,对方回复确认收到,
    然后根据接收到的消息长度来修改自己一次接收消息的大小.
    这个过程多了一次交互

    解决方案2:
    第一种粘包情况可以增加发送消息的时间间隔,等缓冲区的消息发送成功后再发送后续消息

    解决方案3:



    # 粘包现象1 服务端
    
    import socket
    
    server = socket.socket()
    ip_port = ('192.168.15.87', 8001)
    server.bind(ip_port)
    
    server.listen()
    
    conn,addr = server.accept()
    
    from_client_msg1 = conn.recv(1024).decode('utf-8')
    #2000B -- 1024  976B  + 1000B
    from_client_msg2 = conn.recv(1024).decode('utf-8')
    #976+48 = 1024
    print('msg1:',from_client_msg1)
    print('msg2:',from_client_msg2)
    
    conn.close()
    server.close()
    # 粘包现象1 客户端
    import socket
    
    client = socket.socket()
    server_ip_port = ('192.168.15.87', 8001)
    client.connect(server_ip_port)
    client.send('你好!'.encode('utf-8'))
    client.send('天气真好~'.encode('utf-8'))
    
    client.close()
    # 粘包现象_2_服务端
    import socket
    import subprocess
    
    server = socket.socket()
    ip_port = ('192.168.15.87', 8001)
    server.bind(ip_port)
    server.listen(3)
    
    while 1:
        print('等待连接中...')
        tube, addr = server.accept()
        print('连接成功!')
        while 1:
            print('等待接收消息中...')
            cmd = tube.recv(1024).decode('utf-8')
            print('接收命令:%s' % cmd)
            if cmd == 'exit':
                tube.close()
                print('连接已断开!')
                break
            sub_obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            content = sub_obj.stdout.read()   # byte类型,gbk编码
            error = sub_obj.stderr.read()
            len_of_content = str(len(content)).encode('utf-8')
            len_of_error = str(len(error)).encode('utf-8')
            if len(content) == 0:
                print('即将发送消息长度为%s' % len(error))
                tube.send(len_of_error)
                tube.send(error)
    
            else:
                print('即将发送消息长度为%s' % len(content))
                tube.send(len_of_content)
                reply = tube.recv(1024).decode('utf-8')
                if reply == 'ack':
                    print(reply)
                    tube.send(content)
    # 粘包现象_2_客户端
    import socket
    
    client = socket.socket()
    server_ip_port = ('192.168.15.87', 8001)
    client.connect(server_ip_port)
    
    while 1:
        cmd = input('请输入命令>>>')
        client.send(cmd.encode('utf-8'))
        if cmd == 'exit':
            client.close()
            break
        len_of_msg = int(client.recv(1024).decode('utf-8'))
        print('即将接收的消息长度为:%s' % len_of_msg)
        client.send('ack'.encode('utf-8'))
        msg = client.recv(len_of_msg)
        print('实际接收到的消息长度为:%s' % len(msg))
        print(msg.decode('gbk'))
  • 相关阅读:
    剑指 Offer 05. 替换空格
    SNGAN
    CycleGAN
    Robust Pre-Training by Adversarial Contrastive Learning
    FineGAN
    TGAN
    SRGAN
    A Tutorial on Energy-Based Learning
    CoGAN
    EBGAN
  • 原文地址:https://www.cnblogs.com/surasun/p/9804986.html
Copyright © 2011-2022 走看看