zoukankan      html  css  js  c++  java
  • 05python 解决黏包(python网络编程)

    上一章对于TCP通信的黏包现象有了一个初步的认识,可以对黏包下个结论什么叫做黏包?

    其实就是基于TCP通信的时候当我们发送的数据大于接收端可接受的最大数据范围时,这个时候就会产生拆包现象。在了解了这一现象之后就能够解决黏包。

    黏包的两种情况 :一是两个数据特别小,这样会被一次发送出去
                  二是一条数据特别大啊,会被拆分成很多部分多次发送出去
     
    那么到底要如何解决啦?    
       黏包的问题的本质:我们不知道要接受数据的大小        
       首先发送一条信息,显示待发送数据的大小。另一端接收信息,根据显示的大小来 recv( )多大的值        
     

    解决黏包现象

    未使用struck模块解决黏包        
        server端    

     
     
     
    22
     
     
     
     
     
    1
    import socket
    2
    
    
    3
    
    
    4
    sk = socket.socket()
    5
    sk.bind(('127.0.0.1', 8080))
    6
    sk.listen()
    7
    
    
    8
    conn, addr = sk.accept()
    9
    
    
    10
    while True:
    11
        cmd = input('>>>')
    12
        if cmd == 'q':
    13
            conn.send(b'q')
    14
            break
    15
        conn.send(cmd.encode('gbk'))
    16
        num = conn.recv(1024).decode('utf-8')
    17
        conn.send(b'ok')
    18
        res = conn.recv(int(num)).decode('gbk')                 # recv()里面接收的为数字
    19
        print(res)
    20
    
    
    21
    conn.close()
    22
    sk.close()
     
     
     
        client端    

     
     
     
    25
     
     
     
     
     
    1
    import socket
    2
    import subprocess
    3
    
    
    4
    
    
    5
    sk = socket.socket()
    6
    sk.connect(('127.0.0.1', 8080))
    7
    
    
    8
    while True:
    9
        cmd = sk.recv(1024).decode('gbk')
    10
        if cmd == 'q':
    11
            break
    12
        res = subprocess.Popen(cmd, shell=True,
    13
                               stdout=subprocess.PIPE,
    14
                               stderr=subprocess.PIPE
    15
                               )
    16
        std_out = res.stdout.read()                                     # 读取出来的是队列,调用len方法
    17
        # print(std_out.decode('gbk'))
    18
        # print(len(std_out))
    19
        std_err = res.stderr.read()
    20
        sk.send(str(len(std_out) + len(std_err)).encode('utf-8'))       # 这里要注意数字是不能encode的
    21
        sk.recv(1024)
    22
        sk.send(std_out)
    23
        sk.send(std_err)
    24
    
    
    25
    sk.close()
     
     
    导入struct模块解决黏包问题
    struct模块的作用与用法?        
            在网络通信当中,大多传递的数据是以二进制流(binary data)存在的。当传递字符串时,不必担心太多的问题,而当传递诸如int、char之类的基本数据的时候,就需要有一种机制将某些特定的结构体类型打包成二进制流的字符串然后再网络传输,而接收端也应该可以通过某种机制进行解包还原出原始的结构体数据。     
        server    

     
     
     
    23
     
     
     
     
     
    1
    import socket
    2
    import struct
    3
    
    
    4
    
    
    5
    sk = socket.socket()
    6
    sk.bind(('127.0.0.1', 8080))
    7
    sk.listen()
    8
    
    
    9
    conn, addr = sk.accept()
    10
    
    
    11
    while True:
    12
        cmd = input('>>>')
    13
        if cmd == 'q':
    14
            conn.send(b'q')
    15
            break
    16
        conn.send(cmd.encode('gbk'))
    17
        num = conn.recv(4)
    18
        num = struct.unpack('i', num)[0]
    19
        res = conn.recv(int(num)).decode('gbk')          
    20
        print(res)
    21
    
    
    22
    conn.close()
    23
    sk.close()
     
     
     
        client端    

     
     
     
    22
     
     
     
     
     
    1
    import socket
    2
    import struct
    3
    import subprocess
    4
    
    
    5
    
    
    6
    sk = socket.socket()
    7
    sk.connect(('127.0.0.1', 8080))
    8
    while True:
    9
        cmd = sk.recv(1024).decode('gbk')
    10
        if cmd == 'q':
    11
            break
    12
        res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    13
        std_out = res.stdout.read()
    14
        std_err = res.stderr.read()
    15
        len_num = len(std_out)+len(std_err)
    16
        num_bytes = struct.pack('i', len_num)
    17
        sk.send(num_bytes)
    18
        sk.send(std_out)
    19
        sk.send(std_err)
    20
    
    
    21
    sk.close()
    22
    
    
     
     

    补充知识点

            基于struct 模块 实现文件的下载        
            sever端        

     
     
     
    38
     
     
     
     
     
    1
    # 实现一个大文件的上传和下载
    2
    # 匹配文件 IP地址 端口号
    3
    
    
    4
    import socket
    5
    import json
    6
    
    
    7
    
    
    8
    sk = socket.socket()
    9
    sk.bind(('127.0.0.1', 8090))
    10
    sk.listen()
    11
    
    
    12
    buffer = 1024
    13
    conn, addr = sk.accept()
    14
    
    
    15
    head_len = conn.recv(4)                     # 接收四个字节
    16
    head_len = conn.unpack('i', head_len)[0]
    17
    json_head = conn.recv(head_len).decode('utf-8')
    18
    head = json.loads(json_head)
    19
    filesize = head['filesize']
    20
    print(filesize)
    21
    
    
    22
    with open(r'dir\%s' % head['filename'], 'wb') as f:
    23
        while filesize:
    24
            if filesize >= buffer:
    25
                print(filesize)
    26
                content = conn.recv(buffer)
    27
                f.write(content)
    28
                filesize -= buffer
    29
            else:
    30
                content = conn.recv(filesize)
    31
                f.write(content)
    32
                filesize = 0
    33
            print('===>', len(content))
    34
        print(filesize)
    35
    
    
    36
    print('服务器。。。')
    37
    conn.close()
    38
    sk.close()
     
     
     
            client端        

     
     
     
    x
     
     
     
     
     
    1
    import os
    2
    import json
    3
    import struct
    4
    import socket
    5
    
    
    6
    
    
    7
    sk = socket.socket()
    8
    sk.connect(('127.0.0.1', 8090))
    9
    buffer = 4096
    10
    # 发送文件
    11
    head = {'filepath': r'D:DocumentsoCam',
    12
            'filename': r'test.mp4',
    13
            'filesize': None}
    14
    
    
    15
    file_path = os.path.join(head['filepath'], head['filename'])
    16
    filesize = os.path.getsize(file_path)
    17
    head['filesize'] = filesize
    18
    json_head = json.dumps(head)
    19
    bytes_head = json_head.encode('utf-8')
    20
    # 计算head的长度
    21
    head_len = len(bytes_head)
    22
    pack_len = struct.pack('i', head_len)
    23
    sk.send(pack_len)
    24
    sk.send(bytes_head)
    25
    
    
    26
    with open(file_path, 'rb') as f:
    27
        while filesize:
    28
            if filesize >= buffer:
    29
                content = f.read(buffer)
    30
                print('====>', len(content))
    31
                sk.send(content)
    32
                filesize -= buffer
    33
            else:
    34
                content = f.read(filesize)
    35
                sk.send(content)
    36
                filesize = 0
    37
    
    
    38
    sk.close()
    39
    
    
     
     
     
  • 相关阅读:
    K-means聚类算法
    实现计算出用户间的共同好友和二度好友
    Mysql和Hive实现列转行,类似reduceByKey操作
    Flink两阶段提交概述
    一些推荐算法的面试题
    收藏推荐算法-机器学习相关博客文章
    Notepad++将多行数据合并成一行
    布隆过滤器
    二叉树问题
    海量数据常见面试问题
  • 原文地址:https://www.cnblogs.com/pontoon/p/10243031.html
Copyright © 2011-2022 走看看