WebSocket 是一种在单个 TCP 连接上进行
全双工
通信的协议。其最大特点之一就是:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。
golang
语言环境)我这里通过两个库来实现整个WebSocket的开发,这两个库分别是
gin
和gorilla/websocket
。这里有两种方法来获取这两个库,其一就是用go get
,其二是使用git bash
中的git clone
拉取。我使用的是第二种方法,具体使用方法如下。
gorilla/websocket
到GOPATH
的src
下的github.com
目录里面git clone https://github.com/gorilla/websocket
gin-gonic/gin
到GOPATH
的src
下的github.com
目录里面git clone https://github.com/gin-gonic/gin
server
)HTTP
升级成WebSocket
的全局变量upgrade
,并默认允许跨域。var (
upgrade = &websocket.Upgrader{
// 允许跨域
CheckOrigin: func(r *http.Request) bool {
return true
},
}
)
main
函数的结构func main(){
r := gin.Default()
r.GET("/test",func(c *gin.Context){})
err := r.Run(":1234")
if err != nil{
return
}
}
这就是用
gin
框架搭载的一个简单HTTP
服务,这里可以看出WebSocket就是由HTTP
进行升级得到的。现在我们只要把r.GET()
里面的func(c *gin.Context){}
进行封装,即可完善整个服务。
func handler(c *gin.Context) {
// 定义两个变量,其一就是*websocket.Conn,其二就是error
var (
conn *websocket.Conn
err error
)
// 赋值变量,这里就用到了前面定义的upgrade
// conn这结构体内有许多功能,可以都尝试一下,当一般常使用:
// conn.ReadMessage()
// conn.WriteMessage()
// conn.Close()
if conn, err = upgrade.Upgrade(c.Writer, c.Request, nil); err != nil {
return
}
// 为了防止忘记关闭WebSocket连接,使用defer
defer func(conn *websocket.Conn) {
if err = conn.Close(); err != nil {
return
}
}(conn)
// 这里只处理客户端传什么就返回什么
for {
// 定义数据变量
var (
msgType int // 数据类型
data []byte // 数据
errMsg error //错误信息
)
// 接收数据
if msgType, data, errMsg = conn.ReadMessage(); errMsg != nil {
break
}
// 响应数据
if errMsg = conn.WriteMessage(msgType,data); errMsg != nil{
break
}
}
}
这里解释一下为什么说这个使用为什么内部并发不安全,因为
conn.ReadMessage()
和conn.WriteMessage()
这两个接口是并发不安全的,它们在同一时刻不能被不同线程同时调用,否者会使服务中断。具体情况可以在函数里面写过几个goroutine
就可以深刻体会它们的这种不安全
。这就导致了一种情况做不到,就是若是想做一个心跳机制,这里就不能再开一个goroutine
。
main
函数调整func main() {
r := gin.Default()
r.GET("/test", handler)
err := r.Run(":1234")
if err != nil {
return
}
}
只要把
r.GET()
里面的func(c *gin.Context){}
替换成成handler
函数即可。
package main
import (
"github.com/gin-gonic/gin"
"golang.org/websocket"
"net/http"
)
var (
upgrade = &websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
)
func handler(c *gin.Context) {
// 定义两个变量,其一就是*websocket.Conn,其二就是error
var (
conn *websocket.Conn
err error
)
// 赋值变量,这里就用到了前面定义的upgrade
// conn这结构体内有许多功能,可以都尝试一下,当一般常使用:
// conn.ReadMessage()
// conn.WriteMessage()
// conn.Close()
if conn, err = upgrade.Upgrade(c.Writer, c.Request, nil); err != nil {
return
}
// 为了防止忘记关闭WebSocket连接,使用defer
defer func(conn *websocket.Conn) {
if err = conn.Close(); err != nil {
return
}
}(conn)
// 这里只处理客户端传什么就返回什么
for {
// 定义数据变量
var (
msgType int // 数据类型
data []byte // 数据
errMsg error //错误信息
)
// 接收数据
if msgType, data, errMsg = conn.ReadMessage(); errMsg != nil {
break
}
// 响应数据
if errMsg = conn.WriteMessage(msgType,data); errMsg != nil{
break
}
}
}
func main() {
r := gin.Default()
r.GET("/test", handler)
err := r.Run(":1234")
if err != nil {
return
}
}
server
)说明: