zoukankan      html  css  js  c++  java
  • ~~网络编程(六):自定义报头~~

    进击のpython

    *****

    网络编程——自定义报头


    当你正在给你朋友显摆你的代码的时候, 飘过来一个大神随口说道:“这代码有问题”

    大神说的话不能不当真啊,谁让你是个菜鸡,你仔细想了一会儿。嗯,确实有问题

    首先,我刚才做的报头,按照协议来说应该不只有长度信息,还应该有其他信息

    其次就是这个struct模块,它是有长度范围限制的

    struct.pack("i", 10000000000)
    

    这样就会报错,因为你超过他长度了

    这个经过百度,啊,知道了,还有另一种写法

    struct.pack("l", 10000000000)
    

    这样就不会报错了,但是当我后面的数字是100000000000000000,还是报错了

    所以要针对这两点,优化一下代码,也就是自定义报头


    那别的地方都不用改动,我们就看报头部分就行

    首先报头部分的信息用什么类型来存储呢?最好是字典,因为字典有明确的映射关系

    dic = {
        "file_name": "",
        "MD5": "XXXXXXXXXXXXXXXX",
        'file_size': en(stdout) + len(stderr)
    }
    

    好,字典就设定好了!但是,字典类型能用于数据传输吗?

    肯定是不能的啊,所以要把字典转换成为字节模式才行

    那要是这样的话,我就想到了序列化!

    head = json.dumps(dic)
    

    json格式的字符串,能用来发送吗?不能

    所以还要编码一下

    head = head.encode("gbk")
    

    然后就想到了struct模块了,但是她只能接收数字是吧,所以我们可以把报头的长度发过去

    struct.pack("i", len(head))
    

    然后再把报头的信息发过去

    connet.send(head)
    

    最后再发真实数据,那服务端大概就是这样做的

    那客户端呢????

    我应该先解码,然后反序列化,然后拿到的是字典

    最后再通过字典来进行取值操作

    那经过上面的分析,我们可以对代码进行如下修改!

    # 服务端
    import json
    import socket
    import struct
    import subprocess
    
    # 买手机
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 绑定手机卡
    phone.bind(("127.0.0.1", 8080))
    phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # 开机
    phone.listen(5)
    
    # 等电话
    connet, client_addr = phone.accept()
    
    # 收发消息
    while 1:
        try:
            k = connet.recv(1024)
            obj = subprocess.Popen(k.decode("gbk"), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
    
            dic = {
                "file_name": "",
                "MD5": "XXXXXXXXXXXXXXXX",
                'file_size': len(stdout) + len(stderr)
            }
            head = json.dumps(dic)
            head = head.encode("gbk")
            res = struct.pack("i", len(head))
            connet.send(res)
            connet.send(head)
    
            connet.send(stdout)
            connet.send(stderr)
        except ConnectionResetError:
            break
    
    # 挂电话
    connet.close()
    
    # 关机
    phone.close()
    
    # 客户端
    import json
    import socket
    
    # 买手机
    import struct
    
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 拨号
    phone.connect(("127.0.0.1", 8080))
    
    # 发收信息
    while 1:
        msg = input(">>>")
        phone.send(msg.encode("gbk"))
        res = phone.recv(4)
        re_msg = struct.unpack("i", res)[0]
        msg = phone.recv(re_msg)
        msg = msg.decode("gbk")
        msg = json.loads(msg)
        re_len = msg["file_size"]
        re_size = 0
        r = b""  # 我传过来的是字节模式
        while re_size < re_len:
            k = phone.recv(1024)
            r += k
            re_size += len(k)
            print(re_size, re_len)
        print(f'从服务端接收的消息:{r.decode("gbk")}')
    
    connet.close()
    # 关闭
    phone.close()
    
    

    这样我们的这个C/S架构模式就基本成型了

    以后的C/S架构就可以仿照这个模式来进行

    至此,关于粘包问题的解决方案就告一段落了


    *模板嘛*
    *实在不行记下来嘛*
  • 相关阅读:
    linux 解压tgz 文件指令
    shell 脚本没有执行权限 报错 bash: ./myshell.sh: Permission denied
    linux 启动solr 报错 Your Max Processes Limit is currently 31202. It should be set to 65000 to avoid operational disruption.
    远程查询批量导入数据
    修改 MZTreeView 赋权节点父节点选中子节点自动选中的问题
    关于乱码的问题解决记录
    我的网站优化之路
    对设计及重构的一点反思
    我的五年岁月
    奔三的路上
  • 原文地址:https://www.cnblogs.com/jevious/p/11322143.html
Copyright © 2011-2022 走看看