gorilla / websocket

Package gorilla/websocket is a fast, well-tested and widely used WebSocket implementation for Go.

Home Page:https://gorilla.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

concurrent write to websocket connection

go-slark opened this issue · comments

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

concurrent write to websocket connection

Expected Behavior

normal write

Steps To Reproduce

Describe the problem you're having

Using the gorilla/websocket package I sometimes get the following error, despite using mutex.Lock:
concurrent write to websocket connection

Versions

Go version: 1.19
package version: v1.5.1
"Show me the code!"
// goroutine
func (s *Session) write() {
tk := time.NewTicker(interval * 4 / 5)
defer func() {
if e := recover(); e != nil {
// TODO
}
tk.Stop()
s.Close()
}()

for {
	if s.closed.Load() {
		return
	}
	select {
	case m := <-s.out:
		s.conn.SetWriteDeadline(time.Now().Add(wTime))
		err := s.conn.WriteMessage(m.Type, m.Payload)
		if err != nil {
			return
		}
	case <-tk.C:
		s.conn.SetWriteDeadline(time.Now().Add(wTime))
		err := s.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(wTime))
		if err != nil {
			return
		}
	}
}

}

// goroutine
func (s *Session) handleHB() {
s.conn.SetPongHandler(func(msg string) error {
_ = s.conn.SetReadDeadline(time.Now().Add(interval))
atomic.StoreInt64(&s.hbTime, time.Now().Unix())
return nil
})
s.conn.SetPingHandler(func(msg string) error {
_ = s.conn.SetReadDeadline(time.Now().Add(interval))
atomic.StoreInt64(&s.hbTime, time.Now().Unix())
return s.conn.WriteControl(websocket.PongMessage, []byte{}, time.Now().Add(wTime))
})
s.conn.SetCloseHandler(func(code int, text string) error {
return nil
})

for {
	ts := atomic.LoadInt64(&s.hbTime)
	if time.Now().Unix()-ts > int64(s.opt.hbInterval.Seconds()) {
		return
	}
	time.Sleep(interval * 1 / 10)
}

}
from #652 (comment) to know WriteControl and WriteMessage can use at the same time. So, What can cause concurrent write problems.

Anything else?

No response

Hey @go-slark,

Was browsing and saw your issue. Ensure that you're using a mutex for your write operations to prevent any overlap. Kind of like this:

func (s *Session) write() {
   ...
   for {
      ...
      s.writeMutex.Lock()
      select {
      case m := <-s.out:
         ...
         s.writeMutex.Unlock()
         ...
      case <-tk.C:
         ...
         s.writeMutex.Unlock()
         ...
      }
   }
}