【go,聊天室】认识 WebSocket

简介: 【go,聊天室】认识 WebSocket

正文


一、那年毕业设计


学习《Go 语言编程之旅》接着 gRPC 之后,现在开始学 websocket 在 go 语言里的使用了。这里是要跟着做一个聊天室。不禁让我想起那年毕业设计:基于 Java 的即时通讯系统。


大学毕业那会,我一个人搞定了三个毕业设计,一个是邮件收发系统,一个是学生管理系统,我自己的是即时通讯系统。很遗憾,别人的毕设一次性就过了,我自己的反倒去了二辩。不过那时我也不慌,因为都是自己做的,不可能不过。


当时我正在学 Spring 框架,就画了下面的系统架构图,技术栈:HTML 5 + CSS 3 + Jquery + Spring MVC + Spring + Hibernate + MySQL。很遗憾,当时学的是 SpringMVC,其实当时已经有很多人用 SpringBoot 了,因此我选技术的时候就落伍了(当时太年轻,并不是自己选的),这也导致我后来在 Java web 上不愿意再做提升了,就是觉得很遗憾。


7.webp.jpg

系统架构


看看下面界面,这么一个小即时通讯系统,当时觉得还是挺酷的。当时觉得自己懂的好多,HTML 5、 CSS 3 一边学着,学完立马就往即时通讯系统里硬灌,虽然现在看来不成样子,但当时真的特别开心。

记得答辩那天,有个哥们掏出来一个 cmd 命令行程序,界面就是黑窗口,被老师狠狠批了一顿,我当时看着自己的五颜六色的界面,还是挺开心的(虽然四不像,哈哈)。即使一辩挂了回忆还是美美的。


8.webp.jpg


二、WebSocket 简介


WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型的应用层。WebSocket协议在2011年由IETF标准化为RFC 6455,后由RFC 7936补充规范。Web IDL中的WebSocket API由W3C标准化。

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


三、WebSocket 的优点


  • 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
  • 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。
  • 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
  • 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
  • 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。
  • 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。


四、nhooyr.io/websocket 的使用


毕业设计自然是玩笑,其实大半年前,我也做过另一个即时通讯系统,最开始使用的是腾讯云现成的即时通讯SDK,每个月都是收费的,而且聊天记录不能永久保存。后来我基于 Elasticsearch 和 gorilla/websocket 做了系统重构,替代了腾讯云的收费 SDK。

这次使用 nhooyr.io/websocket 是因为教程里用的是这个库,而且写的优点也挺吸引人的,因此我还是愿意再重试一下这个库。

核心特色如下:

  • 有很小且符合 Go 习惯的 API。
  • 核心代码 2200 行。
  • 一流的 context.Context 支持。
  • 有全面的测试。
  • 不依赖任何第三方库。
  • 支持 JSON 和 ProtoBuf。
  • 默认就有高度的性能优化。
  • 开箱即用的并发支持。
  • 全面的 Wasm 支持。
  • CLose handshake。


服务端代码


package main
import (
    "context"
    "fmt"
    "log"
    "net/http"
    "nhooyr.io/websocket"
    "nhooyr.io/websocket/wsjson"
    "time"
)
func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintln(w, "HTTP, Hello")
    })
    http.HandleFunc("/ws", func(w http.ResponseWriter, req *http.Request) {
        conn, err := websocket.Accept(w, req, nil)
        if err != nil {
            log.Println(err)
            return
        }
        defer conn.Close(websocket.StatusInternalError, "内部出错了")
        ctx, cancel := context.WithTimeout(req.Context(), time.Second*10)
        defer cancel()
        var v interface{}
        err = wsjson.Read(ctx, conn, &v)
        if err != nil {
            log.Println(err)
            return
        }
        log.Printf("接收到客户端: %v\n", v)
        err = wsjson.Write(ctx, conn, "Hello WebSocket Client")
        if err != nil {
            log.Println(err)
            return
        }
        conn.Close(websocket.StatusNormalClosure, "")
    })
    log.Fatal(http.ListenAndServe(":2022", nil))
}


客户端代码


package main
import (
    "context"
    "fmt"
    "nhooyr.io/websocket"
    "nhooyr.io/websocket/wsjson"
    "time"
)
func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    defer cancel()
    c, _, err := websocket.Dial(ctx, "ws://localhost:2022/ws", nil)
    if err != nil {
        panic(err)
    }
    defer c.Close(websocket.StatusInternalError, "内部错误!")
    err = wsjson.Write(ctx, c, "Hello WebSocket Server")
    if err != nil {
        panic(err)
    }
    var v interface{}
    err = wsjson.Read(ctx, c, &v)
    if err != nil {
        panic(err)
    }
    fmt.Printf("接收到服务端响应: %v\n", v)
    c.Close(websocket.StatusNormalClosure, "")
}


运行结果

6.webp.jpg

服务端


9.webp.jpg

客户端

目录
相关文章
|
5月前
|
JavaScript 网络协议 前端开发
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
【Nodejs】WebSocket 全面解析+实战演练——(Nodejs实现简易聊天室)
578 0
|
6月前
|
网络协议 Java Go
【Go语言专栏】Go语言中的WebSocket实时通信应用
【4月更文挑战第30天】Go语言(Golang)是Google开发的编程语言,适用于云计算、微服务等领域。本文介绍了WebSocket,一种实现浏览器与服务器全双工通信的协议,其特点是实时性、全双工和轻量级。在Go中实现WebSocket,可以使用gorilla/websocket库。示例展示了如何创建服务器端和客户端,实现消息的收发。WebSocket广泛应用于聊天、游戏、通知推送和实时数据同步等场景。学习Go语言中的WebSocket对于开发实时通信应用至关重要。
230 0
|
3月前
|
缓存 JavaScript 前端开发
为开源项目 go-gin-api 增加 WebSocket 模块
为开源项目 go-gin-api 增加 WebSocket 模块
46 2
|
4月前
|
XML JSON Go
Swoole与Go系列教程之WebSocket服务的应用
在 WebSocket 协议出现之前,Web 应用为了能过获取到实时的数据都是通过不断轮询服务端的接口。轮询的效率、延时很低,并且很耗费资源。
1057 2
Swoole与Go系列教程之WebSocket服务的应用
|
3月前
|
前端开发 Go 开发者
用 Go + WebSocket 快速实现一个 chat 服务
用 Go + WebSocket 快速实现一个 chat 服务
|
3月前
|
网络协议 前端开发 Go
[go笔记]websocket入门
[go笔记]websocket入门
|
4月前
|
存储 前端开发 Go
golang怎么搭建Websocket聊天室服务端
连接的添加和移除 添加连接: 当一个新的WebSocket连接建立时,服务器需要将这个连接添加到全局的连接列表中。多个连接可能同时建立,从而导致多个并发操作试图修改连接列表。 移除连接: 当一个WebSocket连接断开时,服务器需要将这个连接从全局的连接列表中移除。如果多个连接同时断开,可能会导致并发修改连接列表。
|
5月前
|
移动开发 安全 前端开发
技术心得记录:基于webSocket的聊天室
技术心得记录:基于webSocket的聊天室
|
6月前
|
存储 JavaScript Java
基于 WebSocket 打造聊天室
基于 WebSocket 打造聊天室
|
6月前
|
缓存 监控 前端开发
【Go 语言专栏】Go 语言中的 WebSocket 与 Socket.IO 集成
【4月更文挑战第30天】本文介绍了在 Go 语言中集成 WebSocket 与 Socket.IO 的相关技术,WebSocket 是一种高效的双向通信协议,Socket.IO 是一个实时通信库,提供丰富的事件处理。集成两者能实现更强大的实时通信功能。文章讨论了 Go 中 WebSocket 的实现,Socket.IO 与 WebSocket 的关系,集成的意义及步骤,并提醒注意协议兼容性、消息格式等问题。此外,还提到了性能优化策略和应用案例,如实时聊天、数据监控和在线协作工具。通过集成,开发者可以构建出满足多样化需求的实时通信应用。
295 0