百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Golang 的 Websocket 教程

suiw9 2024-11-27 20:40 43 浏览 0 评论

嗨,开发人员!在本教程中,我们将研究如何在我们自己的基于 Go 的程序中使用 WebSockets 来做一些很酷的实时事情。

在本教程结束时,我们应该已经涵盖了以下内容:

  • 什么是 WebSocket
  • 我们如何在 Go 中构建简单的 WebSocket 应用程序

出于本教程的目的,我们将使用该gorilla/websocket软件包,因为我曾在一些生产应用程序中亲自使用它并取得了巨大的成功。

WebSockets - 它们是什么?

因此,我在许多不同的教程中多次介绍了这一点,但始终值得一提的是我们为什么使用 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 main

import "fmt"

func main() {
    fmt.Println("Hello World")
}

让我们通过打开终端、导航到项目目录然后调用go run main.go. 我们应该看到它Hello World在我们的终端中成功输出。

一个简单的 HTTP 端点

我们将从构建一个简单的 HTTP 服务器开始,Hello World只要我们在 port 上点击它就会返回8080。我们还将定义一个简单的 HTTP 端点,它将作为我们将要创建的 WebSocket 端点的基础:

package main

import (
    "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 size
var 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
// endpoint
func 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.go
Hello 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 化我们的应用程序

我在其他许多教程中都谈到了 Docker 的好处,但本质上,它允许我们定义应用程序成功运行所需的确切环境。这意味着您应该能够在 10 年内运行本教程,并且它应该仍然可以完美运行。

FROM golang:1.11.1-alpine3.8
RUN mkdir /app
ADD . /app/
WORKDIR /app
RUN go mod download
RUN 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 的一些主要好处!

相关推荐

俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)

发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...

如何强制所有流量使用 HTTPS一网上用户

如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...

https和http的区别(https和http有何区别)

“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...

快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别

什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...

简述HTTPS工作原理(简述https原理,以及与http的区别)

https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...

21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)

HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...

一次安全可靠的通信——HTTPS原理

为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...

为什么有的网站没有使用https(为什么有的网站点不开)

有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...

HTTPS是什么?加密原理和证书。SSL/TLS握手过程

秘钥的产生过程非对称加密...

图解HTTPS「转」(图解http 完整版 彩色版 pdf)

我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...

HTTP 和 HTTPS 有何不同?一文带你全面了解

随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...

HTTP与HTTPS的区别,详细介绍(http与https有什么区别)

HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...

一文让你轻松掌握 HTTPS(https详解)

一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...

如何在Spring Boot应用程序上启用HTTPS?

HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...

一文彻底搞明白Http以及Https(http0)

早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...

取消回复欢迎 发表评论: