在本教程结束时,我们该当已经涵盖了以下内容:
什么是 WebSocket我们如何在 Go 中构建大略的 WebSocket 运用程序出于本教程的目的,我们将利用该gorilla/websocket软件包,由于我曾在一些生产运用程序中亲自利用它并取得了巨大的成功。
因此,我在许多不同的教程中多次先容了这一点,但始终值得一提的是我们为什么利用 WebSocket 以及它们与传统HTTP要求有何不同。

WebSockets 是升级后的 HTTP 连接,在连接被客户端或做事器终止之前一贯存在。正是通过这个 WebSocket 连接,我们可以实行双工通信,这是一种非常奇特的办法,可以说我们可以利用这个单持续接从我们的客户端与做事器进行通信。
WebSockets 的真正美妙之处在于它们统共利用了 1 个 TCP 连接,并且所有通信都是通过这个单一的龟龄命 TCP 连接完成的。这大大减少了利用 WebSockets 构建实时运用程序所需的网络开销,由于不须要对 HTTP 端点进行持续轮询。
一个大略的例子让我们从一个非常大略的 Go 程序开始,一旦我们可以运行它,我们就可以在它之上构建并开始构建一些大略的 WebSocket 端点。
我们须要首先go modules通过调用来初始化我们的项目以利用:
$ go mod init github.com/elliotforbes/go-websocket-tutorial
这个命令该当go.mod在我们确当前目录中创建一个文件。
完成后,我们可以连续定义我们的main.go文件,我们将在个中进行大部分编码:
main.go
package mainimport "fmt"func main() { fmt.Println("Hello World")}
让我们通过打开终端、导航到项目目录然后调用go run main.go. 我们该当看到它Hello World在我们的终端中成功输出。
一个大略的 HTTP 端点我们将从构建一个大略的 HTTP 做事器开始,Hello World只要我们在 port 上点击它就会返回8080。我们还将定义一个大略的 HTTP 端点,它将作为我们将要创建的 WebSocket 端点的根本:
package mainimport ( "fmt" "log" "net/http")func homePage(w http.ResponseWriter, r http.Request) { fmt.Fprintf(w, "Home Page")}func wsEndpoint(w http.ResponseWriter, r http.Request) { fmt.Fprintf(w, "Hello World")}func setupRoutes() { http.HandleFunc("/", homePage) http.HandleFunc("/ws", wsEndpoint)}func main() { fmt.Println("Hello World") setupRoutes() log.Fatal(http.ListenAndServe(":8080", nil))}
太棒了,当我们考试测验运行它时,go run main.go我们该当看到它成功地启动了我们新定义的 HTTP 做事器,http://localhost:8080随后我们该当能够在我们的浏览器中点击/和/ws路由。
升级 HTTP 连接为了创建 WebSocket 端点,我们实际上须要将传入连接从标准 HTTP 端点升级为持久的 WebSocket 连接。为了做到这一点,我们将利用非常酷的gorilla/websocket软件包中的一些功能!
我们要做的第一件事是定义一个websocker.Upgrader构造。这将保存诸如 WebSocket 连接的读取和写入缓冲区大小之类的信息:
// We'll need to define an Upgrader// this will require a Read and Write buffer sizevar upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024,}
检讨传入来源
我们要添加到现有wsEndpoint函数的下一件事是调用 upgrader.CheckOrigin. 这将确定是否许可来自不同域的传入要求连接,如果不是,它们将被CORS缺点击中。
func wsEndpoint(w http.ResponseWriter, r http.Request) { // remove the previous fmt statement // fmt.Fprintf(w, "Hello World") upgrader.CheckOrigin = func(r http.Request) bool { return true }}
目前,我们保持它非常大略,无论哪个主机考试测验连接到我们的端点,都大略地返回 true。
升级我们的连接我们现在可以开始考试测验利用吸收upgrader.Upgrade()相应写入器和指向 HTTP 要求的指针的函数来升级传入的 HTTP 连接 ,并返回一个指向 WebSocket 连接的指针,或者如果升级失落败则返回缺点。
func wsEndpoint(w http.ResponseWriter, r http.Request) { upgrader.CheckOrigin = func(r http.Request) bool { return true } // upgrade this connection to a WebSocket // connection ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) }}
持续聆听该连接
接下来,我们将要实现一个函数,该函数将持续侦听通过该 WebSocket 连接发送的任何传入。我们reader()现在将调用它,它将吸收一个指向我们从调用中收到的 WebSocket 连接的指针upgrader.Upgrade:
// define a reader which will listen for// new messages being sent to our WebSocket// endpointfunc reader(conn websocket.Conn) { for { // read in a message messageType, p, err := conn.ReadMessage() if err != nil { log.Println(err) return } // print out that message for clarity fmt.Println(string(p)) if err := conn.WriteMessage(messageType, p); err != nil { log.Println(err) return } }}
有了这个定义,我们就可以将它添加到我们的wsEndpoint函数中,如下所示:
func wsEndpoint(w http.ResponseWriter, r http.Request) { upgrader.CheckOrigin = func(r http.Request) bool { return true } // upgrade this connection to a WebSocket // connection ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) } // helpful log statement to show connections log.Println("Client Connected") reader(ws)}
有了所有这些,我们现在该当能够像这样运行我们的新 WebSocket 做事器:
$ go run main.goHello World
太棒了,统统彷佛都见效了!
我之条件到过,WebSockets 许可双工通信,即跨同一个 TCP 连接的来回通信。为了从我们的 Go 运用程序向任何连接的 WebSocket 客户端发送,我们可以ws.WriteMessage() 像这样利用该函数:
func wsEndpoint(w http.ResponseWriter, r http.Request) { upgrader.CheckOrigin = func(r http.Request) bool { return true } // upgrade this connection to a WebSocket // connection ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) } log.Println("Client Connected") err = ws.WriteMessage(1, []byte("Hi Client!")) if err != nil { log.Println(err) } // listen indefinitely for new messages coming // through on our WebSocket connection reader(ws)}
这个添加意味着任何连接到我们的 WebSocket 做事器的客户端都会收到一条好Hi Client!!
末了一步是通过创建客户端并考试测验连接到我们的新 WebSocket 端点来测试是否统统正常。为此,我们将创建一个非常大略的原生 JavaScript 运用程序,它将连接ws://localhost:8080/ws并考试测验通过这个新的 WebSocket 连接发送:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Go WebSocket Tutorial</title> </head> <body> <h2>Hello World</h2> <script> let socket = new WebSocket("ws://127.0.0.1:8080/ws"); console.log("Attempting Connection..."); socket.onopen = () => { console.log("Successfully Connected"); socket.send("Hi From the Client!") }; socket.onclose = event => { console.log("Socket Closed Connection: ", event); socket.send("Client Closed!") }; socket.onerror = error => { console.log("Socket Error: ", error); }; </script> </body></html>
如果我们index.html在浏览器中打开此页面,我们该当在掌握台中看到它已经能够成功连接!
我们还该当在我们的做事器日志中看到客户端已成功连接以及一条Hi From The Client!!
我们现在已经实现了全双工通信!
我在其他许多教程中都谈到了 Docker 的好处,但实质上,它许可我们定义运用程序成功运行所需的确切环境。这意味着您该当能够在 10 年内运行本教程,并且它该当仍旧可以完美运行。
FROM golang:1.11.1-alpine3.8RUN mkdir /appADD . /app/WORKDIR /appRUN go mod downloadRUN go build -o main ./...CMD ["/app/main"]
现在我们已经Dockerfile为我们的运用程序定义了这个,让我们image 利用docker build命令创建,然后让我们考试测验在 Docker 中运行这个 Go WebSocket 运用程序container。
$ docker build -t go-websocket-tutorial .$ docker run -it -p 8080:8080 go-websocket-tutorial
如果统统顺利,我们该当能够看到我们的运用程序在映射到本地机器端口的 docker 容器中启动并运行8080。如果我们http://localhost:8080在浏览器中打开 ,我们该当会看到我们的运用程序返回home page。
结论在本教程中,我们设法先容了 WebSockets 的一些根本知识,以及如何在 Go 中构建一个大略的基于 WebSocket 的运用程序!
因此,希望您喜好本教程并创造它很有用!
我希望这突出了在您自己的 Go 运用程序中利用 WebSockets 的一些紧张好处!