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架构就可以仿照这个模式来进行

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


    *模板嘛*
    *实在不行记下来嘛*
  • 相关阅读:
    Registering an Application to a URI Scheme
    Promise相关网址
    设置table的td宽度,不随文字变宽
    Promise实现原理
    【转】编写高质量代码改善C#程序的157个建议——建议117:使用SSL确保通信中的数据安全
    【转】编写高质量代码改善C#程序的157个建议——建议116:避免用非对称算法加密文件
    【转】编写高质量代码改善C#程序的157个建议——建议115:通过HASH来验证文件是否被篡改
    【转】编写高质量代码改善C#程序的157个建议——建议114:MD5不再安全
    【转】编写高质量代码改善C#程序的157个建议——建议113:声明变量前考虑最大值
    【转】编写高质量代码改善C#程序的157个建议——建议112:将现实世界中的对象抽象为类,将可复用对象圈起来就是命名空间
  • 原文地址:https://www.cnblogs.com/jevious/p/11322143.html
Copyright © 2011-2022 走看看