gorilla/websocket使用教程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gorilla/websocket使用教程相关的知识,希望对你有一定的参考价值。

参考技术A 最近打算为我的网站添加一个服务器资源监视功能,需要服务端主动向前端推动资源占用数据。这时Http则不能达到要求。所以自然想到采用websocket。以前使用SpringBoot时使用websocket很简单,只需要将ServerEndpointExporter注入到bean容器并配合相应注解即可创建一个websocket服务。这里要感谢各位前辈的封装让我们能尽快实现相应的功能,但本次出于学习目并不是公司项目(效率&稳定性至上)同时使用的开发语言为Golang,其web开发生态也不会像Java那样丰富,最后选择了开源实现 gorilla/websocket 项目地址

执行 go get github.com/gorilla/websocket 添加依赖

我们知道websocket由http升级而来,首先会发送附带Upgrade请求头的Http请求,所以我们需要在处理Http请求时拦截请求并判断其是否为websocket升级请求,如果是则调用 gorilla/websocket 库相应函数处理升级请求。

首相要创建Upgrader实例,该实例用于升级请求

其中 CheckOringin 是一个函数,该函数用于拦截或放行跨域请求。函数返回值为 bool 类型,即 true 放行, false 拦截。如果请求不是跨域请求可以不赋值,我这里是跨域请求并且为了方便直接返回 true

此时已经成功升级为websocket连接并获得一个conn实例,之后的发送接收操作皆有conn完成其类型为websocket.Conn。

首先向客户端发送消息使用 WriteMessage(messageType int, data []byte) ,参数1为消息类型,参数2消息内容
示例:

接受客户端消息使用 ReadMessage() 该操作会阻塞线程所以建议运行在其他协程上。该函数有三个返回值分别是,接收消息类型、接收消息内容、发生的错误当然正常执行时错误为 nil。一旦连接关闭返回值类型为-1可用来终止读操作。
示例:

同时可以为连接设置关闭连接监听,函数为 SetCloseHandler(h func(code int, text string) error) 函数接收一个函数为参数,参数为nil时有一个默认实现,其源码为:

可以看到作为参数的函数的参数为int和string类型正好和前端的close(long string)对应即前端调用close(long string)关闭连接后两个参数会被发送给后端并最终被 func(code int, text string) error 所使用。
示例:

则断开连接时将打印code和text

注意:要想使断连处理生效必须要有 ReadMessage() 操作否则不会触发断连处理操作。
以上是常用基础操作点击 官方API手册 学习更多。

最后:大幻梦森罗万象狂气断罪眼\ (••) /

Gorilla Websocket 中的 WriteMessage 和 ReadMessage 是如何工作的?

【中文标题】Gorilla Websocket 中的 WriteMessage 和 ReadMessage 是如何工作的?【英文标题】:How do WriteMessage and ReadMessage in Gorilla Websocket work? 【发布时间】:2021-01-07 16:23:10 【问题描述】:

我正在使用 Gorilla Websocket,并对 WriteMessage 和 ReadMessage 函数的工作原理感到好奇。

WriteMessage 函数是否将字节数据同步发送到客户端?或者ReadMessage是否主动从服务器获取数据(根据文档,我们需要创建一个事件循环来调用ReadMessage函数)。

如果服务器一直在调用WriteMessage,但是没有人读取消息(客户端通过事件循环调用ReadMessage函数),会发生什么情况,是数据丢失了,还是一直保留到下一个读取请求到来?谢谢。

【问题讨论】:

【参考方案1】:

WriteMessage 函数是否同步向客户端发送字节数据?

WriteMessage 将数据写入底层网络连接。

操作系统网络连接维护一个数据缓冲区以传输到对等方。当对端确认对端接收到数据时,数据会从缓冲区中删除。

在所有应用程序数据都添加到缓冲区后,写入操作系统网络连接返回。写可以阻塞等待缓冲区中的空间。

应用程序的写入调用几乎总是在对等方接收到数据之前返回。成功调用 WriteMessage 确实意味着对等应用程序读取了数据。

或者ReadMessage是否主动从服务器获取数据(根据文档,我们需要创建一个事件循环来调用ReadMessage函数)。

ReadMessage 调用读取底层网络连接。

操作系统会缓冲一些从对等端接收到的数据。

读取正在运行的网络连接块,直到缓冲区中的数据可用。

如果服务器一直调用 WriteMessage,但没有人阅读该消息会发生什么。

WriteMessage 最终会阻塞等待操作系统传输缓冲区中的空间。

使用write deadline 来防止永远阻塞死的或卡住的对等体。

数据是丢失了,还是一直保存到下一个读取请求到来?

数据保存在操作系统的发送和接收缓冲区中。

当传输缓冲区已满时,应用程序写入 websocket 连接块。

只有在对等应用程序读取数据之前对等应用程序终止,数据才会丢失。

【讨论】:

【参考方案2】:

您可以在此处找到该函数的源代码:https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L751-L774

看起来这是阻塞/同步方法。

根据跟踪他们在这里创建作家:https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L766

w, err := c.NextWriter(messageType)

然后他们正在写data

if _, err = w.Write(data); err != nil 
    return err

这是阻塞的,因为他们正在关闭该函数的最后一行的连接,所以此时必须编写。

这是io.WriteCloser 接口返回到w 变量的行为。


如果服务器一直在调用WriteMessage,但是没有人读取消息(客户端通过事件循环调用ReadMessage函数),会发生什么情况,是数据丢失了,还是一直保留到下一个读取请求到来?谢谢。

您应该设置写入/读取超时。 图书馆没有为您重复发送数据。您需要在您的应用程序中实现此逻辑。 如果服务器已启动并接收您的连接,(可能)它会读取您的消息(如果在执行您的数据之前没有停止)。 如果您发送消息而服务器已死机(未收到您的消息),您的数据将丢失。

补充参考:

w.Write 函数:https://github.com/gorilla/websocket/blob/c3dd95aea9779669bb3daafbd84ee0530c8ce1c1/conn.go#L650-L675 io.WriteCloser 接口说明:https://golang.org/pkg/io/#WriteCloser Gorila Websocket 超时:https://pkg.go.dev/github.com/gorilla/websocket#Conn.SetReadDeadline Gorila 超时文档:https://pkg.go.dev/github.com/gorilla/websocket#Conn.SetReadDeadline

【讨论】:

应用程序在写入 Gorilla WebSocket 连接时不需要实现重新发送逻辑。 如果您不需要它我同意,但如果出现错误,例如超时或任何其他连接问题,您可能必须实现重试逻辑。这需要在应用层实现。 @CeriseLimón Gorilla Websocket 连接在写入错误后不可用,包括超出期限错误。在websocket连接上重试写是没有意义的。

以上是关于gorilla/websocket使用教程的主要内容,如果未能解决你的问题,请参考以下文章

WebSocket - 关闭握手 Gorilla

golang gorilla websocket例子

go-webSocket——gorilla

Gorilla websocket 错误:关闭 1007 Illegal UTF-8 Sequence

go语言webSocket框架——gorilla

Gorilla Websocket 示例在处理另一个通道时尝试将数据发送到通道时挂起?