No.1 python socketserver 搭建一个TCP server(一)定义协议|8月更文挑战

674 阅读2分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

由于不可言的原因,完整项目代码放在

paste.ubuntu.com/p/Sn5wR3NGR…

最近在做的一个需求,需要和一个C++ Qt程序进行交互,要用到TCP进行数据传输。

于是先写一个demo的测试一下。由于很少写TCP,socket相关的代码,也踩了一些坑,在这里记录一下。

由于这个项目是正在写的,还没完成。这个demo只实现了以下几点功能,之后还会进行优化,实现更多功能 1.支持多个客户端连接server 2.客户端向服务端发送数据(大数据的时候分次切片传输) 3.服务端返回客户端数据 (大数据的时候分次切片传输) 4.用户登录,登出(待完成) 5.广播消息给所有连接的用户(待完成)

首先需要定义一个报文头,实现对对报文头编码解码功能,见MsgHeader

class MsgConstants:
    MSG_TAG = b"xoo6"
    MSG_TAG_LEN = 4
    HEAD_SIZE = 12


class MsgHeader:

    def __init__(self, code=0, length=0, flags=0, version=1):
        self.flags = flags
        self.version = version
        self.code = code
        self.length = length

    def encode(self):
        return struct.pack(">4sBBHI", MsgConstants.MSG_TAG,
                           self.flags, self.version, self.code, self.length)

    def decode(self, data):
        tmp = struct.unpack(">4sBBHI", data)
        self.flags = tmp[1]
        self.version = tmp[2]
        self.code = tmp[3]
        self.length = tmp[4]

用struct包对请求头进行编码和解码,请求头中存储了,是否zlib压缩,版本,请求代码,请求长度, 整体流程如下:

# 服务端应该做两件事
# 循环地从半连接池中取出链接请求与其建立双向链接,拿到链接对象
s = socketserver.ThreadingTCPServer(('127.0.0.1', 8888), MyRequestHandle)
# 处理多个请求
# 如果只想处理一个请求,可以使用ser.handle_request()
s.serve_forever()

服务端,在MyRequestHandle中,处理接收到的请求,完成相应操作后,返回处理的结果,由于处理结果有可能很大,所以先发送一个请求,告知客户端接下来要发送数据的大小,然后循环切片发送数据。

客户端,发送请求给服务端,首先发送请求头,同样由于数据量可能过大,所以也需要先发一个请求头过去,告知服务端本次要发送的数据大小,然后循环切片发送数据。

client = MammothClient()
client.connect('127.0.0.1', 8888)

while True:
    cmd = input('>>>: ').strip()
    if not cmd:
        break
    body_data = cmd * 10000
    head = MsgHeader(614, len(body_data))
    res = client.request(615, head.encode(), body_data.encode())
    print(res)
    print(len(res))

接下来就开始用代码实现对应的服务端,客户端了。