网上各种golang的im聊天项目大致都差不多,b站视频有很多,但唯独有一个讲的很全面,但讲师讲的非常凌乱,知道发现gitee上有一个类似的im源码,才豁然开朗:ctrl/chat.go · 张慧君/Chat - Gitee.com
一、聊天模式架构核心示意图
三种模式:
单机模式
udp分发模式
mq队列发布订阅模式
三、核心架构解释1.首先需要明确的是 message、node 和 clientMap
message消息内容,包含用户相关信息,接收者id,消息类型等。
node 就是一个用户相关信息结构体(不是用户消息体),它包含当前用户的 socket连接、当前用户的接收消息通道chan、当前用户的群id集合(sets集合管理,需要去了解下这个包)
clientMap 是一个全局的字典,用户建立socket连接后,需要通过userid与node关联起来,这样要给某个用户发消息就可以通过userid知道用户所属的连接、通道、所拥有的群组,因为map是全局的,有用户登录就会涉及修改map数据,map线程操作数据不安全,所以要加锁。
2.消息发送、接收实现过程:
2.1单机模式:
a.用户登录后,获取相关node信息,升级为websocket协议并绑定到clientMap,然后给当前用户开启两个子携程,不断进行消息接收和发送。注意:每个用户登录后,服务端都会给这个用户开启两个子携程。
b.所谓消息发送,就是在发送这个子携程下,服务端从当前用户的消息通道chan中取消息,并将消息内容通过socket发送给这个用户的客户端(前端)
c.所谓消息接收,就是在接收这个子携程下,服务端接收当前用户客户端(前端)socket发送过来的消息内容,接收到消息后就需要根据消息本身携带的数据进行判断做出分发,比如消息是单聊还是群聊,单聊接收者id,或群聊,根据群id 和 sets集合知道每个群成员id,知道接收者id就可以通过clientMap查到该用户的node,这样就可以把消息发送到这个用户的消息通道中了。(只要发送到这个用户的通道中即可,因另一个线程会将消息发送给前端)
2.udp分发模式 :
a. udp前两个过程与单机模式前两步(a 、b)一样
b. 当系统配置设置为udp分发模式,客户端socket发送到服务端的消息就会转发到updQueuq队列(chan中),而不是向单机模式那样直接发送到用户所属的消息通道中。
c.当系统配置为udp分发模式时,同时服务端会开启两个子线程,一个子线程负责将updQueuq中的消息取出,通过udp协议广播出去(注意:要理解的是服务端将消息在网路上广播出去)。
d.服务端开启的另一个子携程负责通过udp协议监听网路上的消息,接收到消息后,通过对消息本身携带的数据进行判断(接收者为个人或群组),根据接收者userid拿到接收者用户的node,拿到node就能知道接收者的消息通道,把消息发送到对应接收者用户通道中。(每个用户消息通道中的消息,都会有他们自己的携程将消息socket发送到前端)
3.MQ订阅发布模式
其实mq方式,跟udp处理差不多,就是客户端发送到服务端的消息,在服务端会发送到mq,另一个线程会从mq中取出消息,并分发到对应用户的所属的队列中。
总结:
im发送消息本质就是,一个客户端要给另一个客户端或多个客户端发送消息,客户端与服务端之间的消息交互是通过socket协议进行,至于消息要如何分发出去,需要服务端根据分发情况来处理。其核心还是在于服务端接收到客户端发来的消息如何分发出去。