zoukankan      html  css  js  c++  java
  • 粘包

    什么是粘包:

    一.当服务端发送的数据小于客户端接收数据缓存,且发送数据较快,客户端接收的数据就会出现粘包现象,这是由于tcp协议的优化导致,客户端接收数据时并不知道数据的边界。

    二.当服务端发送的数据大于客户端接收数据的缓存,客户端需要多次从自己的缓存区提取数据,就出现了粘包现象

    解决方法:

    提前告诉客户端接收文件的大小

    方法一:  每次发送数据时,获取数据长度,把数据长度发送给客户端,再发送真实数据

    服务端代码:

    from socket import *
    import subprocess
    import struct
    ip_port = ('127.0.0.1', 8000)
    back_log = 5
    buffer_siza = 1024
    tcp_server = socket(AF_INET, SOCK_STREAM)
    # tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR) #如果当服务端关闭后再打开出现地址重用,无法启用,输入这代码即可解决
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    
    while True:
        conn, addr = tcp_server.accept()
        print('新的客户端链接是:', addr)
        while True:
            try:
                cmd = conn.recv(buffer_siza).decode('utf-8')
                if not cmd:
                    break
                print('收到,开始执行', cmd)
                p1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE,
                                      stdin=subprocess.PIPE)
                stdder = p1.stderr.read()
                 stdout = p1.stdout.read()
                size = len(stdder) + len(stdout)
                date = struct.pack('i', size)
                conn.send(date)
                conn.send(stdder)
                conn.send(stdout)
                print('ok')
            except Exception as e:
                break
        conn.close()

    客户端代码:

    from socket import *
    import struct
    
    ip_port = ('127.0.0.1', 8000)
    buffer_siza = 1024
    tcp_clien = socket(AF_INET, SOCK_STREAM)
    tcp_clien.connect(ip_port)
    
    
    while True:
        msg = input('-->:')
        if not msg:
            continue
        if msg =='stop':
            break
        tcp_clien.send(msg.encode('utf-8'))
        recv_size = 0
        recv_msg = b''
    
    
        t_size = tcp_clien.recv(4)
        size = struct.unpack('i', t_size)[0]
        while recv_size < size:
            recv_msg += tcp_clien.recv(buffer_siza)
            recv_size = len(recv_msg)
        print(recv_msg.decode('gbk'))
    tcp_clien.close()

    方法二:终极版

    通过一个列表,该列表存储文件的一些信息,长度,文件名,md5等信息,先把列表发送,在通过列表里面存的文件大小再接收数据

    服务端

    from socket import *
    import subprocess
    import struct
    import json
    ip_port = ('127.0.0.1', 8000)
    back_log = 5
    buffer_siza = 1024
    tcp_server = socket(AF_INET, SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    while True:
        conn, addr = tcp_server.accept()
        print('新的客户端链接是:', addr)
        while True:
            try:
                cmd = conn.recv(buffer_siza).decode('utf-8')
                if not cmd:
                    break
                print('收到,开始执行', cmd)
                p1 = subprocess.Popen(cmd, shell=True,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE,)
                stdder = p1.stderr.read()
                stdout = p1.stdout.read()
                #建立字典
                header_dic = {
                    'filename': 'a.txt',
                    'md5': 'xxxx',
                    'total_size': len(stdout) + len(stdder)
                }
                #序列化
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
                #发送经过序列化的报头长度
                conn.send(struct.pack('i', len(header_bytes)))
                #发送序列化的真实数据
                conn.send(header_bytes)
                conn.send(stdder)
                conn.send(stdout)
                print('ok')
            except Exception as e:
                break
        conn.close()

    客户端:

    from socket import *
    import struct
    import json
    
    ip_port = ('127.0.0.1', 8000)
    buffer_siza = 1024
    tcp_clien = socket(AF_INET, SOCK_STREAM)
    tcp_clien.connect(ip_port)
    
    
    while True:
        msg = input('-->:')
        if not msg:
            continue
        if msg =='stop':
            break
        tcp_clien.send(msg.encode('utf-8'))
        recv_size = 0
        recv_msg = b''
        #接收报头长度
        obj = tcp_clien.recv(4)
        header_size = struct.unpack('i', obj)[0]
        #接收报头信息
        header_bytes = tcp_clien.recv(header_size)
        #反序列化,提取字典当中存的信息
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
        total_size = header_dic['total_size']
        while recv_size < total_size:
            recv_msg += tcp_clien.recv(buffer_siza)
            recv_size = len(recv_msg)
        print(recv_msg.decode('gbk'))
    tcp_clien.close()
  • 相关阅读:
    电脑无法删除文件提示源路径太长怎么办|电脑由于文件名太长无法删除的解决方法
    史上最清晰的红黑树讲解(上)
    深入理解Java PriorityQueue
    为什么你的博客不够火?
    Java ArrayDeque源码剖析
    Java LinkedList源码剖析
    Java HashSet和HashMap源码剖析
    Java ArrayList源码剖析
    Java Collections Framework概览
    顺序对齐
  • 原文地址:https://www.cnblogs.com/zhengyiqun1992/p/10306647.html
Copyright © 2011-2022 走看看