前言
用Go语言简单实现一个网络聊天室,首先创建一个chatroom的文件夹,在文件夹下创建chatroom.go
文件。
建立tcp socket连接
1 | package main |
启动程序
1 | go run chatroom.go |
nc连接
数据流分析
我们程序中有一个主go程,负责监听。客户端以一种数据流的形式建立连接,这个时候服务器就会启动一个handler()
go程,在handler()
go程中可以接受来自客户端发送的消息。这个时候服务器就应该把消息告诉所有人,因此我们应该在handler()
中创建一个通道,它要将消息写入到公共通道message中,这个时候会有另外一个go程,它负责监听message,当message中有数据时,它会将数据发送给所有的用户。对于user用户的创建我们需要在handler()
中实现,并将user添加到map中,每个用户都有一个自己的msg管道,当需要发送消息给所有用户的时候,go程会遍历用户map,并将消息写入每个用户的管道中。这个时候,每个用户的管道里都会有来自公共管道的message。之后我们再启动一个go程。每个用户都会拥有这个go程,负责将用户自己的msg回写给终端。
定义User和map结构
1 | type User struct { |
在handler中调用
1 | //客户端与服务器建立连接的时候,会有ip和port,因此将port当成user id |
定义message通道
1 | //定义一个message全局通道,用接收任何人发送过来的消息 |
创建监听广播go程函数
1 | //向所有的用户广播消息,启动一个全局唯一的go程 |
启动广播go程
1 | //启动全局唯一的go程,负责监听message通道,写给所有的用户 |
写入上线数据
1 | //向message写入数据,当前用户上线的消息,用于通知所有人 |
当前完整代码
1 | package main |
User监听通道go程
每个用户应该还有一个用来监听自己msg管道的go程,负责将数据返回给客户端。
1 | //每个用户应该还有一个用来监听自己msg管道的go程,负责将数据返回给客户端。 |
当前完整代码
1 | package main |
增加功能
查询用户
查询命令:who 将当前所有登陆的用户,展示出来,id,name返回给当前用户
在handler中处理业务逻辑
1 | //1.查询当前所有的用户 who |
重命名
1 | else if len(userInput) >9 && userInput[:7]=="\\rename" { |
主动退出
从map中删除,对应的conn要close
每个用户都有自己的watch go程,负责监听退出信号
1 | //启动一个go程,负责监听退出信号,触发后进行清理工作:delete map,close conn都在这里处理 |
在handler函数中定义isQuit
1 | //定义一个退出信号,用户监听client退出 |
在handler中启动go watch,同时传入相应信息
1 | //启动go程,负责监听退出信号 |
在conn.Read(buf)
之后,通过读取的cnt判断用户退出,如果是ctrl+c主动退出,则触发isQuit
1 | if cnt == 0 { |
超时退出
使用定时器来进行超时管理。如果60s内没有发送任何数据,那么直接将这个连接关闭掉
更新watch函数
1 | //启动一个go程,负责监听退出信号,触发后进行清理工作:delete map,close conn都在这里处理 |
创建并传入restTimer
1 | //创建一个用于重置计数器的管道,用于告知watch函数,当前用户正在输入 |
只要有数据写入,每次写入数据之后都要设置restTimer
1 | restTimer <- true |
聊天室完整代码
1 | package main |