設計思路:每個websocket允許的連接都是有時間限制的,超時后服務端會自動斷開連接,那么長連接就在服務端發出斷開連接信息后客戶端檢測斷開信息再次發起連接請求,中間再通過握手信息確保客戶端同服務器處於連接狀態。
設計結構:
- type Longsocket struct {
- Ws *websocket.Conn
- writeCh chan []byte
- readCh chan []byte
- ShakeHand bool
- Url string
- Protocol string
- Origin string
- BufferSize int
- Status int
- mu sync.Mutex
- }
長連接通過`writeCh`通道主動向連接方發送消息,通過`ReadCh`通道讀取連接中的信息,設置`ShakeHand`來確定是否要發送握手信息,Status用以標識連接狀態。
通過WriteLoop來發送握手信息,同時監聽`WriteCh`通道,轉發通道里的消息。
- //call func with a gorouting, it will send shake hands message to service to make sure self is ok
- //if you want to send message call func 'Write', and the case writeCh will be vaild
- func (l *Longsocket) WriteLoop() {
- defer func() {
- if err := recover(); err != nil {
- //fmt.Println("writeloop", err)
- }
- }()
- for {
- errCount := 0
- if l.Status != STATUS_CONNECT {
- break
- }
- select {
- case <-time.After(time.Second * time.Duration(SHAKE_HANDS_FREQUENCY)):
- if l.ShakeHand {
- _, err := l.Ws.Write([]byte(SHAKE_HANDS_MSG))
- if err != nil {
- errCount++
- }
- }
- case msg := <-l.writeCh:
- _, err := l.Ws.Write(msg)
- if err != nil {
- errCount++
- }
- }
- if errCount != 0 {
- break
- }
- }
- l.Close()
- }
通過ReadLoop來接受信息,同時將消息轉發到`ReadCh`通道內。
- //read message form socket and write them to readCh
- func (l *Longsocket) ReadLoop() {
- defer func() {
- if err := recover(); err != nil {
- //fmt.Println("readloop", err)
- }
- }()
- for {
- if l.Status != STATUS_CONNECT {
- break
- }
- buf := make([]byte, l.BufferSize)
- n, err := l.Ws.Read(buf)
- if err != nil {
- break
- }
- if n > 0 {
- l.readCh <- buf[0:n]
- }
- }
- l.Close()
- }
然后可以通過Read函數將消息轉發到形如
type dealmsg func([]byte, *Longsocket) error
的函數中去做相應的消息處理,當然你也可以通過Longsocket參數發送相應的處理消息。
源碼已上傳githup如下,其中有demo供參考。
https://github.com/qianlnk/longsocket