golang 实现并发的websocket

公司要求使用golang做识别系统的web后端,我采用gin框架开发,其中部分功能使用了websocket实现前后端的实时消息推送刷新。

记录一下golang中使用channel和锁将websocket封装成为可并发读写的websocket:

package cws

import (
	"errors"
	"github.com/gorilla/websocket"
	"sync"
)

//封装websocket并发读写操作

type Connection struct {
	WsConn    *websocket.Conn
	InChan    chan []byte
	OutChan   chan models.BayDataS
	CloseChan chan byte
	Mutex     sync.Mutex
	IsClosed  bool
}

func InitConnection(wsConn *websocket.Conn) (conn *Connection, err error) {
	conn = &Connection{
		WsConn:    wsConn,
		InChan:    make(chan []byte, 1000),
		OutChan:   make(chan []byte, 1000),
		CloseChan: make(chan byte, 1),
	}
	//读协程
	go conn.ReadLoop()
	//写协程
	go conn.WriteLoop()
	return
}

func (conn *Connection) ReadMess() (data []byte, err error) {
	select {
	case data = <-conn.InChan:
	case <-conn.CloseChan:
		err = errors.New("connection is closed")
	}
	return
}

func (conn *Connection) WriteMes(data []byte) (err error) {
	select {
	case conn.OutChan <- data:
	case <-conn.CloseChan:
		err = errors.New("connection is closed")
	}
	return
}

func (conn *Connection) Close() {
	conn.Close() //本身线程安全,可重入
	//加锁,只能执行一次
	conn.Mutex.Lock()
	if !conn.IsClosed {
		close(conn.CloseChan)
		conn.IsClosed = true
	}
}

//具体实现读消息
func (conn *Connection) ReadLoop() {
	var (
		data []byte
		err  error
	)
	for {
		if _, data, err = conn.WsConn.ReadMessage(); err != nil {
			goto ERR
		}
		select {
		case conn.InChan <- data:
		case <-conn.CloseChan:
			goto ERR
		}
	}
ERR:
	conn.Close()
}

//具体实现写消息
func (conn *Connection) WriteLoop() {
	var (
		data models.BayDataS
		err  error
	)
	for {
		select {
		case data = <-conn.OutChan:
		case <-conn.CloseChan:
			goto ERR
		}
		if err = conn.WsConn.WriteMessage(websocket.TextMessage, data); err != nil {
			goto ERR
		}
	}
ERR:
	conn.Close()
}

当然websocket支持发送和接收的消息多种,像我的话常用的是Json 如:

conn.WsConn.WriteJSON(data) //data可以是struct,map等
posted @ 2020-06-18 23:56  cfclang  阅读(3791)  评论(1编辑  收藏  举报