目的:搭建websocket服务,用浏览器与服务进行消息交互(写的第一个Go程序)
代码目录结构:
前端html页面:

server.go代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package
main
import
(
"fmt"
"github.com/gorilla/websocket"
"go_websocket"
"net/http"
)
// http升级websocket协议的配置
var
wsUpgrader = websocket.Upgrader{
// 允许跨域CORS
CheckOrigin:
func
(r *http.Request) bool {
return
true
},
}
// 消息处理
func
wsHandler(resp http.ResponseWriter, req *http.Request) {
wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)
if
err != nil {
return
}
wsConn := go_websocket.WsConnectionInit(wsSocket)
wsConn.Run()
for
{
wsmsg, err := wsConn.ReadMessage()
if
err != nil {
goto
error
}
err = wsConn.WriteMessage(wsmsg)
if
err != nil {
goto
error
}
}
error:
fmt.Println(
"websocket is closed"
)
return
}
func
main() {
fmt.Println(
"websocket start"
)
http.HandleFunc(
"/ws"
, wsHandler)
http.ListenAndServe(
"0.0.0.0:7777"
, nil)
}
|
connection.go代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package
go_websocket
import
(
"errors"
"fmt"
"github.com/gorilla/websocket"
"sync"
"time"
)
// 客户端读写消息
type
WsMessage
struct
{
msgType int
data []byte
}
// 客户端连接
type
wsConnection
struct
{
wsSocket *websocket.Conn
inChan
chan
*WsMessage
outChan
chan
*WsMessage
isClosed bool
closeChan
chan
[]byte
mutex sync.Mutex
}
// 连接初始化
func
WsConnectionInit(wsSocket *websocket.Conn) (wsConn *wsConnection) {
wsConn = &wsConnection{
wsSocket: wsSocket,
inChan: make(
chan
*WsMessage, 1000),
outChan: make(
chan
*WsMessage, 1000),
closeChan: make(
chan
[]byte, 1),
}
return
wsConn
}
// 启动
func
(wsConn *wsConnection) Run() {
go
wsConn.readLoop()
go
wsConn.writeLoop()
go
wsConn.heartbeat()
}
// 心跳检测
func
(wsConn *wsConnection) heartbeat() {
for
{
time.Sleep(2 * time.Second)
wsmsg := &WsMessage{msgType: websocket.TextMessage, data: []byte(
"heartbeat"
)}
err := wsConn.WriteMessage(wsmsg)
if
err != nil {
fmt.Println(
"send heartbeat stop"
)
return
}
}
}
// 循环接收
func
(wsConn *wsConnection) readLoop() {
var
()
for
{
msgType, data, err := wsConn.wsSocket.ReadMessage()
if
err != nil {
goto
error
}
select
{
case
wsConn.inChan <- &WsMessage{msgType: msgType, data: data}:
case
<-wsConn.closeChan:
goto
closed
}
}
error:
wsConn.Close()
closed:
fmt.Println(
"readLoop closed"
)
}
// 循环发送
func
(wsConn *wsConnection) writeLoop() {
for
{
select
{
case
wsmsg := <-wsConn.outChan:
if
err := wsConn.wsSocket.WriteMessage(wsmsg.msgType, wsmsg.data); err != nil {
goto
error
}
case
<-wsConn.closeChan:
goto
closed
}
}
error:
wsConn.Close()
closed:
fmt.Println(
"writeLoop close"
)
}
// 取消息,外部可调用
func
(wsConn *wsConnection) ReadMessage() (wsmsg *WsMessage, err error) {
select
{
case
wsmsg = <-wsConn.inChan:
return
wsmsg, nil
case
<-wsConn.closeChan:
return
nil, errors.New(
"websocket is closed"
)
}
}
// 写消息,外部可调用
func
(wsConn *wsConnection) WriteMessage(wsmsg *WsMessage) (err error) {
select
{
case
wsConn.outChan <- wsmsg:
case
<-wsConn.closeChan:
return
errors.New(
"websocket is closed"
)
}
return
nil
}
// 关闭wsSocket
func
(wsConn *wsConnection) Close() {
wsConn.wsSocket.Close()
// 加锁
wsConn.mutex.Lock()
if
!wsConn.isClosed {
wsConn.isClosed = true
close(wsConn.closeChan)
}
wsConn.mutex.Unlock()
}
|
效果展示: