慢聊Go之GoLang中使用Gorilla Websocket|Go主题月

简介: 慢聊Go之GoLang中使用Gorilla Websocket|Go主题月

前言

下雨声,伴随着窗外的车的声音。心中,思索自己的梦与想。

今天,我们来聊一下,GoLang中的Websocket使用。正如,我们在学习Java的Websocket时候,可能需要一个细致的学习过程。今天,我们就好好收拾心情,

学习走起!

WebSocket

首先,我们先来好好学习下,WebSocket是个什么鬼。以下呢,摘自  百度百科。

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

Gorilla Websocket

在Go中编写websocket客户端/服务器的功能,在GoLang中使用Gorilla Websocket软件包。主要的存储库代码位于Github上

现在让我们了解如何使用Gorilla快速设置可测试的Websocket应用程序。

安装Gorilla Websocket Go软件包

除了可以运行的Go编译器之外,没有其他依赖项,因此您只需要使用即可go get

go get github.com/gorilla/websocket

Websocket应用程序设计

在继续进行任何示例之前,让我们首先设计一个需要完成的工作的粗略布局。

任何使用websocket协议的应用程序通常都需要一个客户端和一个服务器

服务器程序绑定到服务器上的端口,并开始侦听任何Websocket连接。与连接有关的详细信息由websocket协议定义,该协议通过原始HTTP连接起作用。

客户端程序尝试使用websocket URL与服务器建立连接。请注意,尽管Gorilla为我们提供了用于编写客户端的API,但无需使用Golang来实现客户端程序。

如果您的Web应用程序使用单独的前端,则通常Websocket客户端将以该语言(Javascript等)实现。

但是,出于说明的目的,我们将在Go中同时编写客户端程序和服务器程序。

现在,让我们的客户端-服务器体系结构运行!

我们将为server.go服务器和client.go客户端提供一个程序。

使用Gorilla Websockets –创建我们的服务器

该websocket服务器将在常规的http服务器上实现。我们将net/http用于提供原始HTTP连接。

现在,在中server.go,让我们编写常规的HTTP服务器,并添加一个socketHandler()函数来处理websocket逻辑。

// server.go
package main
import (
    "log"
    "net/http"
    "time"
    "github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{} // use default options
func socketHandler(w http.ResponseWriter, r *http.Request) {
    // Upgrade our raw HTTP connection to a websocket based one
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Print("Error during connection upgradation:", err)
        return
    }
    defer conn.Close()
    // The event loop
    for {
        messageType, message, err := conn.ReadMessage()
        if err != nil {
            log.Println("Error during message reading:", err)
            break
        }
        log.Printf("Received: %s", message)
        err = conn.WriteMessage(messageType, message)
        if err != nil {
            log.Println("Error during message writing:", err)
            break
        }
    }
}
func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Index Page")
}
func main() {
    http.HandleFunc("/socket", socketHandler)
    http.HandleFunc("/", home)
    log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

Gorilla的工作是转换原始HTTP连接进入一个有状态的websocket连接。

这就是为什么使用struct调用Upgrader来帮助我们的原因。

我们使用全局升级程序变量通过来帮助我们将任何传入的HTTP连接转换为websocket协议upgrader.Upgrade()。这将返回给我们*websocket.Connection,我们现在可以使用它来处理websocket连接。

服务器使用读取消息,然后使用conn.ReadMessage()写入消息conn.WriteMessage()

该服务器只是将所有传入的Websocket消息回显到客户端,因此这说明了如何将Websocket用于全双工通信。

现在让我们转到的客户端实现client.go

创建我们的客户端程序

我们还将使用Gorilla编写客户端。这个简单的客户端将每隔1秒钟不断发出消息。如果我们的整个系统按预期工作,则服务器将接收间隔为1秒的数据包,并回复相同的消息。

客户端还将具有接收传入的Websocket数据包的功能。在我们的程序中,我们将有一个单独的goroutine处理程序receiveHandler,用于侦听这些传入的数据包。

// client.go
package main
import (
    "log"
    "os"
    "os/signal"
    "time"
    "github.com/gorilla/websocket"
)
var done chan interface{}
var interrupt chan os.Signal
func receiveHandler(connection *websocket.Conn) {
    defer close(done)
    for {
        _, msg, err := connection.ReadMessage()
        if err != nil {
            log.Println("Error in receive:", err)
            return
        }
        log.Printf("Received: %s\n", msg)
    }
}
func main() {
    done = make(chan interface{}) // Channel to indicate that the receiverHandler is done
    interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully
    signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
    socketUrl := "ws://localhost:8080" + "/socket"
    conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
    if err != nil {
        log.Fatal("Error connecting to Websocket Server:", err)
    }
    defer conn.Close()
    go receiveHandler(conn)
    // Our main loop for the client
    // We send our relevant packets here
    for {
        select {
        case <-time.After(time.Duration(1) * time.Millisecond * 1000):
            // Send an echo packet every second
            err := conn.WriteMessage(websocket.TextMessage, []byte("Hello from GolangDocs!"))
            if err != nil {
                log.Println("Error during writing to websocket:", err)
                return
            }
        case <-interrupt:
            // We received a SIGINT (Ctrl + C). Terminate gracefully...
            log.Println("Received SIGINT interrupt signal. Closing all pending connections")
            // Close our websocket connection
            err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
            if err != nil {
                log.Println("Error during closing websocket:", err)
                return
            }
            select {
            case <-done:
                log.Println("Receiver Channel Closed! Exiting....")
            case <-time.After(time.Duration(1) * time.Second):
                log.Println("Timeout in closing receiving channel. Exiting....")
            }
            return
        }

如果您观察代码,您会发现我创建了两个通道doneinterrupt用于receiveHandler()和之间的通信main()

我们使用无限循环使用select来通过通道监听事件。我们conn.WriteMessage()每秒钟写一条消息。如果激活了中断信号,则所有未决的连接都将关闭,并且我们可以正常退出!

嵌套select是为了确保两件事:

  • 如果receiveHandler通道退出,则通道'done'将关闭。这是第一个case <-done条件
  • 如果'done'通道未关闭,则在1秒钟后会有超时,因此程序将在1秒钟超时后退出

通过使用通道仔细处理所有情况select,您可以拥有一个可以轻松扩展的最小体系结构。

最后,让我们看看同时运行客户端和服务器时获得的输出!

输出

image.png

动图点此查看

总结

学习是一件持续的事情,我们今天学习了Websocket的使用。

加油同志们,不变的努力!!

目录
相关文章
|
4月前
|
JSON Go 开发者
go-carbon v2.5.0 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
carbon 是一个轻量级、语义化、对开发者友好的 Golang 时间处理库,提供了对时间穿越、时间差值、时间极值、时间判断、星座、星座、农历、儒略日 / 简化儒略日、波斯历 / 伊朗历的支持。
97 4
|
4月前
|
缓存 监控 前端开发
Go 语言中如何集成 WebSocket 与 Socket.IO,实现高效、灵活的实时通信
本文探讨了在 Go 语言中如何集成 WebSocket 与 Socket.IO,实现高效、灵活的实时通信。首先介绍了 WebSocket 和 Socket.IO 的基本概念及其优势,接着详细讲解了 Go 语言中 WebSocket 的实现方法,以及二者集成的重要意义和具体步骤。文章还讨论了集成过程中需要注意的问题,如协议兼容性、消息格式、并发处理等,并提供了实时聊天、数据监控和在线协作工具等应用案例,最后提出了性能优化策略,包括数据压缩、缓存策略和连接管理优化。旨在帮助开发者更好地理解并应用这些技术。
188 3
|
4月前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
243 1
|
4月前
|
存储 Cloud Native Shell
go库介绍:Golang中的Viper库
Viper 是 Golang 中的一个强大配置管理库,支持环境变量、命令行参数、远程配置等多种配置来源。本文详细介绍了 Viper 的核心特点、应用场景及使用方法,并通过示例展示了其强大功能。无论是简单的 CLI 工具还是复杂的分布式系统,Viper 都能提供优雅的配置管理方案。
121 6
|
4月前
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
|
6月前
|
存储 Go
Golang语言基于go module方式管理包(package)
这篇文章详细介绍了Golang语言中基于go module方式管理包(package)的方法,包括Go Modules的发展历史、go module的介绍、常用命令和操作步骤,并通过代码示例展示了如何初始化项目、引入第三方包、组织代码结构以及运行测试。
179 3
|
6月前
|
Go
golang语言之go常用命令
这篇文章列出了常用的Go语言命令,如`go run`、`go install`、`go build`、`go help`、`go get`、`go mod`、`go test`、`go tool`、`go vet`、`go fmt`、`go doc`、`go version`和`go env`,以及它们的基本用法和功能。
159 6
|
7月前
|
Go 开发者
|
7月前
|
Go 开发者
什么是 Golang 包?详解 Go 语言的包系统
【8月更文挑战第31天】
112 0
|
7月前
|
前端开发 Go 开发者
用 Go + WebSocket 快速实现一个 chat 服务
用 Go + WebSocket 快速实现一个 chat 服务