系列文章目录
跟着😽猫猫学Golang,快人一步
系列初开,跟着我走进Go 语言的世界里🌍
系列目录
Golang 从零开始实现多人聊天室(一)服务端监听
Golang 从零开始实现多人聊天室(二)客户端访问
文章目录
- 系列文章目录
- 😺前言
- 项目代码持续更新
- 一、服务端 client
- 1.接收的消息转发至其他客户端
- 2.通知其他人上线
- 3.通知上线新Op
- 二、客户端 client
- 1.接收服务端的通知消息
- 2.发送登录消息
- 3.公屏聊天
- 😽总结
😺前言
运用 go 里面的net包中的相关方法来实现一个基于tcp的简单多人聊天室
实现
- 加入聊天室
- 广播通知
- 公屏聊天
- 群聊
- 单聊
- 退出
建立文件目录进行服务端与客户端区分
服务端代码就写在server 文件夹下的 server 文件中
客户端代码就写在cliemt 文件夹下的 client文件中
项目代码持续更新
多人聊天室
https://github.com/moercat/go-chatroom
此时更新到服务端转发
一、服务端 client
1.接收的消息转发至其他客户端
修改 Read,即当服务端接收到消息时,通过接受链接的客户端信息映射 ConnMap来转发给每一个客户端,从而实现通信
func (m Message) Read() {// 统一消息格式fmt.Printf("%v 用户[%s]: %v \n", time.Now().Format("2006-01-02 15:04:05"), m.Name, m.Msg)for _, client := range ConnMap {msg := fmt.Sprintf("%v [%s]: %v", time.Now().Format("2006-01-02 15:04:05"), m.Name, m.Msg)_, err := client.Conn.Write([]byte(msg))if err != nil {fmt.Println("client Conn Error")return}}}
2.通知其他人上线
通过上文实现了服务端的广播通信,那么也就可以实现通知功能,来优化用户体验?
答案肯定是可以的,那么如何做呢,和广播通知同理,通过消息映射找出每一个客户端后转发
// 提醒所有人新用户上线
func (m Message) ntyLogin() {for _, client := range ConnMap {msg := fmt.Sprintf("%v [%s]: %v", time.Now().Format("2006-01-02 15:04:05"), m.Name, "I Login")_, err := client.Conn.Write([]byte(msg))if err != nil {fmt.Println("new user Conn Error")continue}}
}
3.通知上线新Op
不断接收用户输入结果,得到用户的昵称、操作 Op 后可以正式进行我们的通信操作,定义一个 msg 的 Say 函数专门处理发送至服务端的信息
const (Read = iota + 1QuitNtyLogin // 通知上线的Op
)
改进服务端Op表
switch cMsg.Op {case Read:cMsg.Read()case Quit:case NtyLogin:cMsg.ntyLogin()default:fmt.Println("无效OP")}
此时当我们接收到 Op 为2的操作时,将会对所有成员通知该用户此时上线
二、客户端 client
1.接收服务端的通知消息
每一个客户端单独开一个协程进行接收消息,与发送分离,防止发送消息
因为接收导致阻塞
go baseMsg.Receive(conn)
func (m Message) Receive(conn net.Conn) {for {data := make([]byte, 255)ml, err := conn.Read(data)if ml == 0 || err != nil {// 收到的参数错误忽略、continue}fmt.Println(string(data[:ml]))}
}
2.发送登录消息
通过之前我们了解到 Op 的含义,那么服务端我们也需要维护一份Op表,那么 Login 我们定义为 2
const (Say = iota + 1QuitLogin
)
那么我们也不允许用户可以通过发送登录信息来不同的广播自己的登录信息
switch msg.Op {case Say:msg.Say(conn)case Quit:msg.Quit(conn)case Login:fmt.Println("您已登录,输入无效,请重新输入")default:fmt.Println("输入无效op,请重新输入")}
通过约定好的协议模型,来当调用时进行单次的登录信息广播
func (m Message) Login(conn net.Conn) {msg := m.Name + "|" + strconv.Itoa(Login) + "|"_, err := conn.Write([]byte(msg))if err != nil {fmt.Println("通知服务端登录信息发送失败")return}
}
当我们登陆时,我们可以知道我们
3.公屏聊天
由于服务端实现了转发,也就是每一个客户端的信息都会被服务端广播给同个服务器的所有人,那么此时我们也就达到了公屏聊天的需求
😽总结
🎶感谢您看到这里🎶
从零开始实现一个基于Go的多人在线聊天室,功能包括:单聊、群聊、昵称、上下线通知、聊天日志等等,
通过服务端的转发,我们可以收到了其他客户端的消息,这牌篇博文也就达成了我们所需要的上线通知与公屏聊天,那么下篇博文将会重点在退出与重新登陆,将会通过代码简单的实现消息记录的存储,将每个人尽量保留聊天记录。多人在线聊天室只是一个简单的使用场景,那么不断地为自己提需求就是学习的动力。