~~网络编程(六):自定义报头~~

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

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


*模板嘛*
*实在不行记下来嘛*
posted @ 2019-08-04 00:00  吃夏天的西瓜  阅读(733)  评论(0编辑  收藏  举报