cst同步使用”golang.org/x/net/websocket”和gorilla区别

[TOC]

心跳处理方面

gorilla

  • 从源码可以看出每当遇到ping、pong的数据帧的时候,都会有一个处理函数,gorilla提供了以下的接口去设置这一个处理函数,这样就可以在后端来发ping,然后查看客户端是否有回复pong
    //-----pong
    func (c *Conn) SetPongHandler(h func(appData string) error) {
    if h == nil {
        h = func(string) error { return nil }
    }
    c.handlePong = h
    }
    //-----ping
    func (c *Conn) SetPingHandler(h func(appData string) error) {
    if h == nil {
        h = func(message string) error {
            err := c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
            if err == ErrCloseSent {
                return nil
            } else if _, ok := err.(net.Error); ok {
                return nil
            }
            return err
        }
    }
    c.handlePing = h
    }
  • 因此后端可以这样处理pong
    • 说明:当客户端没有任何操作的时候,在读操作的阻塞中,收到pong或者ping是不会接触阻塞的,因此无法重新开始循环更新读超时,但是通过这样的操作可以一直用心跳来更新读超时
    //设置心跳处理函数
    conn.SetPongHandler(func(appData string) error {
        client.Conn.SetReadDeadline(time.Now().Add(PongWait))
        // fmt.Println("Pong")
        return nil
    })
    //-----读操作
    for {
        //设置读超时
        conn.SetReadDeadline(time.Now().Add(PongWait))
     //这里在消息来到之前会阻塞
        _, msg, err := client.Conn.ReadMessage()
        if err != nil {
            if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
                client.logger.Info("读超时,error:" + err.Error())
                return nil
            } else if websocket.IsCloseError(err, websocket.CloseGoingAway) {
                client.logger.Info("client of id:" + client.UserID + " close going away")
                return nil
            } else if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
                client.logger.Info("client of id:" + client.UserID + " closed normally")
                return nil
            }
            client.logger.Error("Client of id:" + client.UserID + " ReadMessage Error: " + err.Error())
            return fmt.Errorf("Client of id:%s ReadMessage Error: %v", client.UserID, err)
      }
    }
  • gorilla源码
    switch frameType {
    case PongMessage:
        if err := c.handlePong(string(payload)); err != nil {
            return noFrame, err
        }
    case PingMessage:
        if err := c.handlePing(string(payload)); err != nil {
            return noFrame, err
        }
    case CloseMessage:
        closeCode := CloseNoStatusReceived
        closeText := ""
        if len(payload) >= 2 {
            closeCode = int(binary.BigEndian.Uint16(payload))
            if !isValidReceivedCloseCode(closeCode) {
                return noFrame, c.handleProtocolError("bad close code " + strconv.Itoa(closeCode))
            }
            closeText = string(payload[2:])
            if !utf8.ValidString(closeText) {
                return noFrame, c.handleProtocolError("invalid utf8 payload in close frame")
            }
        }
        if err := c.handleClose(closeCode, closeText); err != nil {
            return noFrame, err
        }
        return noFrame, &CloseError{Code: closeCode, Text: closeText}
    }

golang.org/x/net/websocket

  • 从源吗我们可以看出,这个库是定死了收到pong帧或者ping帧的操作,而且收到pong和ping帧后它也是不会解除读操作的阻塞的
  • 因此我想到的方法就是前端来发ping来维持前后端的联系
  • golang.org/x/net/websocket源码
    switch frame.PayloadType() {
    case ContinuationFrame:
        frame.(*hybiFrameReader).header.OpCode = handler.payloadType
    case TextFrame, BinaryFrame:
        handler.payloadType = frame.PayloadType()
    case CloseFrame:
        return nil, io.EOF
    case PingFrame, PongFrame:
        b := make([]byte, maxControlFramePayloadLength)
        n, err := io.ReadFull(frame, b)
        if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
            return nil, err
        }
        io.Copy(io.Discard, frame)
        if frame.PayloadType() == PingFrame {
            if _, err := handler.WritePong(b[:n]); err != nil {
                return nil, err
            }
        }
        return nil, nil
    }

关闭连接的处理

gorilla

  • gorilla提供了检测错误码的接口,因此我们可以很容易根据状态码来查看用户的退出是否是正常的
    func IsCloseError(err error, codes ...int) bool {
    if e, ok := err.(*CloseError); ok {
        for _, code := range codes {
            if e.Code == code {
                return true
            }
        }
    }
    return false
    }

golang.org/x/net/websocket

  • 这个库并没有提供检测状态码的操作,并且它也没有将状态码暴露出来,遇到关闭帧的时候马上就会返回io.EOF,因此假如想要查看状态码做一些更细节的操作,就不能把状态码放到关闭帧里面。
    switch frame.PayloadType() {
    case ContinuationFrame:
        frame.(*hybiFrameReader).header.OpCode = handler.payloadType
    case TextFrame, BinaryFrame:
        handler.payloadType = frame.PayloadType()
    case CloseFrame:
        return nil, io.EOF
    case PingFrame, PongFrame:
        b := make([]byte, maxControlFramePayloadLength)
        n, err := io.ReadFull(frame, b)
        if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
            return nil, err
        }
        io.Copy(io.Discard, frame)
        if frame.PayloadType() == PingFrame {
            if _, err := handler.WritePong(b[:n]); err != nil {
                return nil, err
            }
        }
        return nil, nil
    }

Tags:

Comments are closed

       

粤公网安备44011302004556号