Socket 客户端和服务端建立长链接、实现消息推送
go-socket.io
是 go 语言实现长链接第三方包
安装
go get github.com/googollee/go-socket.io
在项目使用
本项目基于 gitee.com/shizidada/m… 基础之上开发的
创建 socket
修改 main.go 添加
// init socket io
server, err := socketio.NewServer(nil)
if err != nil {
log.Fatal(err)
}
go server.Serve()
defer server.Close()
// 在 router 添加注册 Socket
router.InitSocket(app, server)
创建 SocketController
controller -> socket_controller.go
package controller
import (
"fmt"
"log"
"github.com/gin-gonic/gin"
socketio "github.com/googollee/go-socket.io"
)
type SocketController struct{}
func (sc *SocketController) RegisterSocket(engine *gin.Engine, server *socketio.Server) {
}
注册 controller,添加路由绑定
router -> router.go
package router
import (
"moose-go/controller"
v1 "moose-go/controller/v1"
"github.com/gin-gonic/gin"
)
func InitRouter(app *gin.Engine) {
new(v1.UserController).RegisterSocket(app)
// 添加这一行
new(controller.SocketController).RegisterSocket(app)
}
初始化 socket
在 SocketController RegisterSocket 挂载 socket 到 gin 引擎上
engine.GET("/socket.io/*any", gin.WrapH(server))
engine.POST("/socket.io/*any", gin.WrapH(server))
server.OnConnect("/", sc.onConnect)
server.OnError("/", sc.onError)
server.OnDisconnect("/", sc.onDisconnect)
server.OnEvent("/", "SINGLE_CHAT", sc.onSingleChat)
server.OnEvent("/", "BYE", sc.onBye)
socket 监听
func (sc *SocketController) onConnect(s socketio.Conn) error {
s.SetContext("")
s.Emit("CONNECT", "欢迎连接 ~ ")
return nil
}
func (sc *SocketController) onError(s socketio.Conn, e error) {
fmt.Println("meet error:", e)
}
func (sc *SocketController) onDisconnect(s socketio.Conn, reason string) {
fmt.Println("closed", reason)
}
func (sc *SocketController) OnSingleChat(s socketio.Conn, message map[string]string) {
fmt.Printf("%v \n", message)
}
func (sc *SocketController) onBye(s socketio.Conn) string {
last := s.Context().(string)
s.Emit("BYE", last)
s.Close()
return last
}
启动服务
go run main.go
测试通信
使用之前写的 dart
模块 socket_io_client
作为客户端
import 'dart:async';
import 'package:dartlearn/src/template/message_template.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
import 'package:socket_io_client/socket_io_client.dart';
main(List<String> args) {
String toUserId = '775113183131074580';
String currentUserId = '786600935907659776';
IO.Socket channel = IO.io(
'http://localhost:8090',
OptionBuilder()
// for Flutter or Dart VM
.setTransports(['websocket'])
// disable auto-connection
.disableAutoConnect()
// optional
// .setExtraHeaders({'access_token': accessToken})
.build());
channel.connect();
// 链接建立成功之后,可以发送数据到socket.io的后端了
channel.on('connect', (data) => print('connect $data'));
// 链接建立失败时调用
channel.on('error', (data) => print('error $data'));
// 链接出错时调用
channel.on("connect_error", (data) => print('connect_error: $data'));
// 链接断开时调用
channel.on('disconnect', (data) => print('disconnect $data'));
// 链接关闭时调用
channel.on('close', (data) => print('close $data'));
// 服务端 emit 一个 message 事件时,可以直接监听到
channel.on('message', (data) => print('onmessage $data'));
channel.on('SINGLE_CHAT', (data) => print('收到消息 $data'));
Timer.periodic(Duration(seconds: 3), (timer) {
MessageTemplate template = MessageTemplate(
type: "MS:TEXT",
chatType: "CT:SINGLE",
sendId: currentUserId,
receiveId: toUserId,
content: "测试消息");
channel.emit('SINGLE_CHAT', template.toJson());
});
}
服务端可以正常收到客户端消息
消息接收需要保持一致
客户端提交 json 格式消息,服务端需要用 map[string]string
使用结构体接收消息
创建 Message 结构体
type Message struct {
Type string `json:"type"`
ChatType string `json:"chatType"`
SendId string `json:"sendId"`
ReceiveId string `json:"receiveId"`
Content string `json:"content"`
}
修改 onSingleChat
func (sc *SocketController) onSingleChat(s socketio.Conn, message Message) {
fmt.Printf("%v \n", message.Content)
}