Project address: github.com/Benny66/gin…

Websocket is briefly

Using Webcocket communication compared to HTTP, it is not like HTTP is stateless request, each time HTTP data query, processing needs to be re-initiated, three handshakes, four waves, while WebSocket only needs to make a TCP connection. You can maintain a persistent connection to continuously send and reply messages, and enable the server to push real-time messages to the client, which is not possible with HTTP.

registered

The client sends a request, and the server keeps the request (registration) and maintains communication using heartbeat, which requires the server to maintain an interface to accept the client’s connection requests

Func WsClient(context *gin.Context) {upGrande := websocket.upgrader {// Set to allow cross-domain CheckOrigin: Func (r * http.request) bool {return true}, // Set the Request protocol Subprotocols: []string{context.getheader (" sec-websocket-protocol ")},} // Create connection conn, err := upGrande.Upgrade(context.writer, context.Request, nil) if err ! = nil { log.WSLog(fmt.Sprintf("websocket connect error: %s", Context.param ("channel")) format.newresponsejson (context).error (51001) return} // Generate client_id var uUID = uuid.NewV4().String() client := &ws.Client{ Id: uuid, Socket: conn, Message: Make (chan, byte [], 1024),} / / registered ws. WebsocketManager. RegisterClient (client) / / coroutines, Go client.read () go client.write ()}Copy the code

The above interface is an entry (interface) for client connection, which needs to be configured on the router route

r.GET("/ws", api.WsClient)
Copy the code

The connection address of the client can be ws://127.0.0.1:8066/ws

After the application server is started, a coroutine is started in the background to monitor and process the messages sent to the client, including: client registration, client logout, and reply to the client message

for { select { case client := <-manager.Register: Group[client.id] = client Manager.clientCount += 1 log.wslog (fmt.sprintf (" client.sprintf ")) Client id %s", client.id) manager.lock.unlock () Case Client := < -manager.unregister: Manager.lock.lock () if _, ok := manager.group [client.id]; Ok {// close the Message channel close(client.message) // delete the customer from the Group delete(manager.group, Client.id) // Number of clients reduced by 1 manager.clientCount -= 1 log.wslog (fmt.sprintf (" Client logout: The client id for % s ", client id))} manager. Lock. The Unlock () case data: = < - manager. BroadCastMessage: // broadcast data to all clients for _, conn := range manager.Group { if data.IsBroadCast { conn.Message <- data.Message } else { if function.InSliceStr(conn.Id, data.ClientIDs) { conn.Message <- data.Message } } } } }Copy the code

Client structure of a single WebSocket

type Client struct {
  Id      string
  Socket  *websocket.Conn
  Message chan []byte
}

Copy the code

The server side WebSocke structure

type Manager struct { //client.id => Client Group map[string]*Client Lock sync.Mutex Register, UnRegister Chan *Client BroadCastMessage Chan *BroadCastMessageData clientCount uint // Number of groups and clients}Copy the code

Reply to the data message structure

type BroadCastMessageData struct {
  Message     []byte
  IsBroadCast bool
  ClientIDs   []string
}

Copy the code

Data communication

The following is a flowchart of normal data communication (sending data, replying data) after a connection has been established

In the process of client message logic processing, encapsulates a handle file, receive client request instruction function method processing

/** * Description: webSocket server receive data call function * author: shahao * create on: 2021-04-16 18:05:21 */ func (manager *Manager) ServerCodeToFunc(data ReadData) { funcName := case2Camel(data.Actioncode)  vft := manager.serverReturnFunc() params := make([]reflect.Value, 1) params[0] = reflect.ValueOf(data) if vft[funcName].IsValid() { vft[funcName].Call(params) } }Copy the code

You can then place the processing logic set into serverInstructFunc for processing, such as the heartbeat reply function

Func (m *ServerMethod) HeartBeat(params ReadData) {webSocketManager.success (params.actionCode, true, params.IsBroadCast, params.ClientIDs) }Copy the code

Other articles

Previous article on frameworks: A self-encapsulated Go-Gin based Web services framework