[TOC]
go-chat
使用Go基于WebSocket的通讯聊天软件。
功能列表:
- 登录注册
- 修改头像
- 群聊天
- 群好友列表
- 单人聊天
- 添加好友
- 添加群组
- 文本消息
- 剪切板图片
- 图片消息
- 文件发送
- 语音消息
- 视频消息
- 屏幕共享(基于图片)
- 视频通话(基于WebRTC的p2p视频通话)
- 分布式部署(通过kafka全局消息队列,统一消息传递,可以水平扩展系统)
后端
代码仓库 go中协程是非常轻量级的。在每个client接入的时候,为每一个client开启一个协程,能够在单机实现更大的并发。同时go的channel,可以非常完美的解耦client接入和消息的转发等操作。
通过go-chat,可以掌握channel的和Select的配合使用,ORM框架的使用,web框架Gin的使用,配置管理,日志操作,还包括proto buffer协议的使用,等一些列项目中常用的技术。
后端技术和框架
- web框架Gin
- 长连接WebSocket
- 日志框架Uber的zap
- 配置管理viper
- ORM框架gorm
- 通讯协议Google的proto buffer
- makefile 的编写
- 数据库MySQL
- 图片文件二进制操作
前端
基于react,UI和基本组件是使用ant design。可以很方便搭建前端界面。
界面选择单页框架可以更加方便写聊天界面,比如像消息提醒,可以在一个界面接受到消息进行提醒,不会因为换页面或者查看其他内容影响消息接受。 前端代码仓库: https://github.com/kone-net/go-chat-web
前端技术和框架
- React
- Redux状态管理
- AntDesign
- proto buffer的使用
- WebSocket
- 剪切板的文件读取和操作
- 聊天框发送文字显示底部
- FileReader对文件操作
- ArrayBuffer,Blob,Uint8Array之间的转换
- 获取摄像头视频(mediaDevices)
- 获取麦克风音频(Recorder)
- 获取屏幕共享(mediaDevices)
- WebRTC的p2p视频通话
截图
语音,文字,图片,视频消息
视频通话
屏幕共享
消息协议
protocol buffer协议
syntax = "proto3";
package protocol;
message Message {
string avatar = 1; //头像
string fromUsername = 2; // 发送消息用户的用户名
string from = 3; // 发送消息用户uuid
string to = 4; // 发送给对端用户的uuid
string content = 5; // 文本消息内容
int32 contentType = 6; // 消息内容类型:1.文字 2.普通文件 3.图片 4.音频 5.视频 6.语音聊天 7.视频聊天
string type = 7; // 如果是心跳消息,该内容为heatbeat
int32 messageType = 8; // 消息类型,1.单聊 2.群聊
string url = 9; // 图片,视频,语音的路径
string fileSuffix = 10; // 文件后缀,如果通过二进制头不能解析文件后缀,使用该后缀
bytes file = 11; // 如果是图片,文件,视频等的二进制
}
选择协议原因
通过消息体能看出,消息大部分都是字符串或者整型类型。通过json就可以进行传输。那为什么要选择google的protocol buffer进行传输呢?
- 一方面传输快 是因为protobuf序列化后的大小是json的10分之一,是xml格式的20分之一,但是性能却是它们的5~100倍.
- 另一方面支持二进制 当我们看到消息体最后一个字段,是定义的bytes,二进制类型。 我们在传输图片,文件,视频等内容的时候,可以将文件直接通过socket消息进行传输。 当然我们也可以将文件先通过http接口上传后,然后返回路径,再通过socket消息进行传输。但是这样只能实现固定大小文件的传输,如果我们是语音电话,或者视频电话的时候,就不能传输流。
快速运行
运行go程序
go环境的基本配置 ...
拉取后端代码
git clone https://github.com/kone-net/go-chat
进入目录
cd go-chat
拉取程序所需依赖
go mod download
MySQL创建数据库
CREATE DATABASE chat;
修改数据库配置文件
vim config.toml
[mysql]
host = "127.0.0.1"
name = "chat"
password = "root1234"
port = 3306
table_prefix = ""
user = "root"
修改用户名user,密码password等信息。
创建表
将chat.sql里面的sql语句复制到控制台创建对应的表。
在user表里面添加初始化用户
手动添加用户。
运行程序
go run cmd/main.go
运行前端代码
配置React基本环境,比如nodejs ...
拉取代码
git clone https://github.com/kone-net/go-chat-web
进入目录
cd go-chat-web
安装前端基本依赖
npm install
如果后端地址或者端口号需要修改 放在服务器运行时一定需要修改后端地址
修改src/chat/common/param/Params.jsx里面的IP_PORT
运行前端代码默认启动端口是3000
npm start
访问前端入口
http://127.0.0.1:3000/login
分布式部署
- 拉取代码 将代码拉取到服务器,运行make build构建后端代码。
- 构建后端服务镜像
进入目录deployments/docker
通过目录下的Dockerfile构建镜像
docker build -t konenet/gochat:1.0 .
- 部署服务 需要部署nginx进行反向代理,mysql保存数据,1个或者多个后端服务。
- 在config.toml中配置分布式消息队列 将msgChannelType中的channelType修改为kafka,就为分布式消息队列。需要填写消息队列对应的地址和topic ```toml appName = "chat_room"
[mysql] host = "mysql8" name = "go-chat-message" password = "thepswdforroot" port = 3306 tablePrefix = "" user = "root"
[log] level = "debug" path = "logs/chat.log"
[staticPath] filePath = "web/static/file/"
[msgChannelType] channelType = "kafka"
kafkaHosts = "kafka:9092" kafkaTopic = "go-chat-message"
* 启动服务
通过deployments/docker下的docker-compose.yml进行启动。
docker-compose up -d
* 注意:分布式部署后,上传的文件视频等,可能会因为负载到不同的机器上,导致文件找不到的情况,所以需要一个在线或者分布式文件服务器。
## 代码结构
├── Makefile 代码编译,打包,结构化等操作 ├── README.md ├── api controller类,对外的接口,如添加好友,查找好友等。所有http请求的入口 │ └── v1 ├── assets │ └── screenshot 系统使用到的资源,markdown用到的截图文件 ├── bin 打包的二进制文件 ├── chat.sql 整个项目的SQL ├── cmd │ └── main.go main函数入口,程序启动 ├── config │ └── toml_config.go 系统全局的配置文件配置类 ├── config.toml 配置文件 ├── deployments │ └── docker docker构建镜像,docker-compose.yml等文件 ├── go.mod ├── go.sum ├── internal │ ├── dao 数据库 │ ├── kafka kafka消费者和生产者 │ ├── model 数据库模型,和表一一对应 │ ├── router gin和controller类进行绑定 │ ├── server WebSocket中消息的接受和转发的主要逻辑 │ └── service 调用的服务类 ├── logs ├── pkg │ ├── common 常量,工具类 │ ├── errors 封装的异常类 │ ├── global 封装的日志类,使用时不会出现第三方的包依赖 │ └── protocol protoc buffer自动生成的文件,定义的prot