这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战
由于不可言的原因,完整项目代码放在
最近在做的一个需求,需要和一个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))
接下来就开始用代码实现对应的服务端,客户端了。