websocketBase.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package controllers
  2. import (
  3. "errors"
  4. "sync"
  5. "github.com/gorilla/websocket"
  6. )
  7. // wsConn TODO:封装的基本结构体
  8. type wsConn struct {
  9. inChan chan []byte
  10. outChan chan []byte
  11. closeChan chan []byte
  12. isClose bool // 通道closeChan是否已经关闭
  13. mutex sync.Mutex
  14. conn *websocket.Conn
  15. }
  16. // InitWebSocket TODO:初始化Websocket
  17. func InitWebSocket(conn *websocket.Conn) (ws *wsConn, err error) {
  18. ws = &wsConn{
  19. inChan: make(chan []byte, 1024),
  20. outChan: make(chan []byte, 1024),
  21. closeChan: make(chan []byte, 1024),
  22. conn: conn,
  23. }
  24. // 完善必要协程:读取客户端数据协程/发送数据协程
  25. go ws.readMsgLoop()
  26. go ws.writeMsgLoop()
  27. return
  28. }
  29. // InChanRead TODO:读取inChan的数据
  30. func (conn *wsConn) InChanRead() (data []byte, err error) {
  31. select {
  32. case data = <-conn.inChan:
  33. case <-conn.closeChan:
  34. err = errors.New("connection is closed")
  35. }
  36. return
  37. }
  38. // InChanWrite TODO:inChan写入数据
  39. func (conn *wsConn) InChanWrite(data []byte) (err error) {
  40. select {
  41. case conn.inChan <- data:
  42. case <-conn.closeChan:
  43. err = errors.New("connection is closed")
  44. }
  45. return
  46. }
  47. // OutChanRead TODO:读取inChan的数据
  48. func (conn *wsConn) OutChanRead() (data []byte, err error) {
  49. select {
  50. case data = <-conn.outChan:
  51. case <-conn.closeChan:
  52. err = errors.New("connection is closed")
  53. }
  54. return
  55. }
  56. // OutChanWrite TODO:inChan写入数据
  57. func (conn *wsConn) OutChanWrite(data []byte) (err error) {
  58. select {
  59. case conn.outChan <- data:
  60. case <-conn.closeChan:
  61. err = errors.New("connection is closed")
  62. }
  63. return
  64. }
  65. // CloseConn TODO:关闭WebSocket连接
  66. func (conn *wsConn) CloseConn() {
  67. // 关闭closeChan以控制inChan/outChan策略,仅此一次
  68. conn.mutex.Lock()
  69. if !conn.isClose {
  70. close(conn.closeChan)
  71. conn.isClose = true
  72. }
  73. conn.mutex.Unlock()
  74. //关闭WebSocket的连接,conn.Close()是并发安全可以多次关闭
  75. _ = conn.conn.Close()
  76. }
  77. // readMsgLoop TODO:读取客户端发送的数据写入到inChan
  78. func (conn *wsConn) readMsgLoop() {
  79. for {
  80. // 确定数据结构
  81. var (
  82. data []byte
  83. err error
  84. )
  85. // 接受数据
  86. if _, data, err = conn.conn.ReadMessage(); err != nil {
  87. goto ERR
  88. }
  89. // 写入数据
  90. if err = conn.InChanWrite(data); err != nil {
  91. goto ERR
  92. }
  93. }
  94. ERR:
  95. conn.CloseConn()
  96. }
  97. // writeMsgLoop TODO:读取outChan的数据响应给客户端
  98. func (conn *wsConn) writeMsgLoop() {
  99. for {
  100. var (
  101. data []byte
  102. err error
  103. )
  104. // 读取数据
  105. if data, err = conn.OutChanRead(); err != nil {
  106. goto ERR
  107. }
  108. // 发送数据
  109. if err = conn.conn.WriteMessage(1, data); err != nil {
  110. goto ERR
  111. }
  112. }
  113. ERR:
  114. conn.CloseConn()
  115. }