动手实现一个消息代理
2.8 本节简介
自己动手写一个代理.
我们可以将客户的消息直接发往服务中,一般http操作是由客户端发起的,因此http协议很适合作为客户端触发事件的协议,当有客户发起事件时,服务直接响应,这里有一个逆向的过程,当服务端的票数存量发生变化,或者服务有实时的消息需要通知响应状态的客户端时,服务推送消息给客户端.
这里假设我们有成千上万的客户在触发该事件(比如订票,付款等),我们不希望这些操作直接与服务的数据库交互,让他们模拟现实人类的情况,排队处理吧. 这时候消息代理的用场就出现了.
2.8.0 接入服务
我们将动物园的预定消息,通过代理服务发布到订阅者那里。 本质上讲,代理服务将数据取出,并转发到相关频道的全部用户中。
缓存的可以帮助我们提高速度,经常需要查询的房间 放到缓存中 将帮助提高 软件 响应速度。
在矩阵中inspect 是类似的 作用
类型检查、获取源代码、检查类与函数、检查解释器的调用堆栈
insoect.getfullargspec()
获取可调用对象参数的名称和默认值。
返回一个包含七件事的元组:
(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)。
'args' 是参数名称的列表。
'varargs' 和 'varkw' 是 * 和 ** 参数的名称或 None。
'defaults' 是最后 n 个参数的默认值的 n 元组。
'kwonlyargs' 是一个仅包含关键字的参数名称列表。
'kwonlydefaults' 是一个将名称从 kwonlyargs 映射到默认值的字典。
“注释”是将参数名称映射到注释的字典。
与inspect.signature()的显着区别:
- 始终报告“self”参数,即使是绑定方法
- 由 __wrapped__ 定义的包装链 * 不* 自动解包
我们在这一小节使用代理,监控动物园的预定信息,它们通过缓存发布到代理服务中。
2.8.1 创建代理处理函数
将动物园的订购信息,发布到对应的订阅者客户端, 我们获取消息的主题信息, 并根据主题封装消息,最后返回给对应客户端
func DealMsg(txt string, msgMap map[string]string, stream *Proxyer) bool {
msgMap["message"] = txt
bstr, err := json.Marshal(msgMap)
if err != nil {
return false
}
m := stream.MsgTopic(bstr)
return stream.PublishSendToSuber(websocket.TextMessage, m.Topic, []byte(bstr))
}
将接收到的消息,发给相关的订阅者用户
PublishSendToSuber(msgType int, topic string, payload []byte) bool {
var ss bool = true
for _, p := range ps.Subscriptions {
if topic != p.Topic {
continue
}
sf := p.Clients.send(websocket.TextMessage, payload)
}
而代理管理者,保持了相关用户和订阅者的信息,必然哪些客户端订阅了 该 topic
Proxyer struct {
Clients []*WsClient
Subscriptions []Subscribes
}
订阅者客户端具体信息如下,保存客户端信息:
Subscribes struct {
Topic string
Clients *WsClient
}
并且通过ConnMsg , 从目标服务拉取并保持消息操作
func ConnMsg(stream *Proxyer) {
go func() {
SubService(stream)
}()
}
最后在接口 message 中绑定该消息代理服务
wsHandler(ctx *gin.Context) {
....
go proxyer.ConnMsg(Ps)
}
GET("/message" wsHandler)
如此,在有参观者预定动物园票据时,我们将可以从代理得到实时的消息。
2.8.2 消息接收和观测
在客户端保持连接时,如果该客户端预定了相关主题的消息,服务器将实时的返回给对应的客户端。
使用启动服务
go run main.go
浏览器连接 127.0.0.1:3002
在浏览器控制台:
客户端二 先订阅预定信息
client2.send('{"action":"subscribe","topic":"booked" }')
客户端一预定票据时
client1.send('{"action":"publish","topic":"booked", "message":"1673254205340:2199:32925:en00030"}')
客户端二 将实时接收消息并在浏览器界面显示
{"action":"publish","message":"1673254205340:2119:32925:en00030","topic":"booked"}
使用效果
从以下地址获取代理服务,
使用示例代理程序,其地址为:
完整获取该目录
https://github.com/hahamx/examples/tree/main/service/proxyer/
执行
./proxyer.exe
启动时指定您本地的缓存地址,比如:
这将触发提示键入缓存地址,
请键入缓存地址,例如:localhost:6379 : localhost:6379
board monitor::3002
打开浏览器,访问地址 http://127.0.0.1:3002/ 将获得如下提示
Welcome to ws client.
connected to server:ws://localhost:3002/message
最后使用客户端模拟预定 动物园门票 , 这与上一节 2.6 的使用方式的一致,就不再重复。
效果如下:
![](https://bbs-img.huaweicloud.com/blogs/img/20240222/1708566942695584039.png)
3 小结
这是一个从0实现的 简单的消息代理服务,与主服务不同,它可以在任何地方使用。 当有人在主服务器预定票据时,在代理服务中可以实时观测到。
以此做为一个队列服务,可以实现预定商品的买卖和生产。
本节示例程序地址:
https://github.com/hahamx/examples/tree/main/service/proxyer/
本部分完。
- 点赞
- 收藏
- 关注作者
评论(0)