客户端和服务端建立长链接、实现消息推送|Go主题月

2,391 阅读2分钟

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)
}

重新启动服务也是可以正常接收