很多APP都需要主动向用户推送消息,这就需要用到长连接的服务,即我们通常提到的websocket,同样也是使用socket服务,通信协议是基本类似的,在go中用的最多的、也是最简单的socket服务就是gorilla/websocket,它有21.1K的star,足以说明它的受欢迎程度, 它的github地址是 https://github.com/gorilla/websocket,我们的长连接服务也是通过gorilla/websocket改造出来的。

websocket的简单使用

我们使用的版本是1.3.0,首先下载websocket

go get github.com/gorilla/websocket@v1.3.0

把websocket/examples/echo下面的 client.go server.go 现在下来拷贝到项目里面。

https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/server.go

https://github.com/gorilla/websocket/blob/v1.3.0/examples/echo/client.go

在一个终端执行 websocket 服务

go run server.go

recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889
recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605
recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325
recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866
recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108
recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310
recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266

再打开一个终端执行 go run client.go,充当客户端

connecting to ws://localhost:8080/echo
recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889
recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605
recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325
recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866
recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108
recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310
recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266

我们看看这个简单的例子。

client.go

go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}() ticker := time.NewTicker(time.Second)
defer ticker.Stop() for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt") // Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}

go func() 的 c.ReadMessage 不停的从socket里面读取数据并且打印。

for 循环不停的从1秒的定时器里面读取时间,写到socket

server.go

	for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}

for c.ReadMessage 循环不停的从 socket读取数据,把数据打印之后,又写给客户端。

这是大致的websocket 客户端与服务端通信的简单例子。

改成自定义的协议

我们使用二进制数据流,自定义的协议是这样的,

先是无符号的 uint 占4个字节,表示行为逻辑,比如111-获取信息, 110- 加好友等等

后面是具体的数据,跟HTTP请求的GET或者POST参数类似,具体数据格式定义好就行,比如可以使用JSON数据、可以使用RPC定义好的数据格式

修改完之后 client.go 代码是这样的

	for {
select {
case <-done:
return
case <-ticker.C:
buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, uint32(110))
binary.Write(buf, binary.BigEndian, []byte("我们都好"))
err := c.WriteMessage(websocket.BinaryMessage, buf.Bytes())
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt") // Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}

主要是这个

buf := bytes.NewBuffer([]byte{})
binary.Write(buf, binary.BigEndian, uint32(110))
binary.Write(buf, binary.BigEndian, []byte("我们都好"))

创建一个bytes Buffer

写入一个uint32,占4个字节,表示行为逻辑

写入行为逻辑具体的数据

以上采用大端通信

修改之后的 server.go

	for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Println("messagetype:%d", mt) log.Println("messagelen:%d", len(message)) log.Println("messagetype:%d", binary.BigEndian.Uint32(message[0:4])) log.Println("recv: %s", string(message[4:]))
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}

mt websocket 类型

TextMessage = 1 文本类型传传输

BinaryMessage = 2 字节类型传输

从socket里面获取到message之后

先取前4个字节,表示逻辑行为

再取剩余的字节,表示行为逻辑需要的参数

我们重新执行一下,server.go 和 client.go

go run client.go
connecting to ws://localhost:8080/echo
recv: n我们都好
recv: n我们都好 go run server.go
messagetype:%d 2
messagelen:%d 16
messagetype:%d 110
recv: %s 我们都好

messagetype=2表示二进制通信

message长度是16,前四个字节是无符号整形,四个汉字占12个字节,一共16个字节,无符号uint是110表示加好友。

这就是一个简单自定义协议的socket服务。

如果有需要登录鉴权的话,在server.go中可以从r *http.Request 获取header或者cookie,进行登录鉴权验证。

生产的部署

因为是 websocket 协议,如果有代理服务器的话,需要在各代理服务器上的Nginx做协议升级,将HTTP 升级为 websocket ,比如下面的代理服务器。

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
} server {
listen 80;
location /serv/ { proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade; proxy_connect_timeout 3;
proxy_redirect off;
proxy_read_timeout 3600;
proxy_send_timeout 3600; proxy_pass http://push_web/serv/;
}
}

golang开发 gorilla websocket的使用的更多相关文章

  1. golang gorilla websocket例子

    WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. WebSocket通信协议于2011年被IETF定 ...

  2. miniblink+golang开发windows gui应用

    golang的优点自不必说了,这么好的语言怎么能缺少界面库呢?所以我使用miniblink开发了一个可以用html,css,js开发界面的浏览器,通过它你能为你的golang开发简单的界面.说白了其实 ...

  3. Golang 开发技能图谱

    # Golang 开发技能图谱 ## Go 语言环境搭建- Go 安装- GOPATH 与工作空间- Go 命令- Go开发工具 ## GO 语言编程基础- 关键词和语法(Language Synta ...

  4. 使用golang 开发的 andriod应用

    最近在捣鼓一个东东,就是使用golang开发andriod应用.说起来简单操作起来还挺麻烦,中间又学习了很多东西.比如ubuntu,docker,angular,ionic,jquery mobile ...

  5. golang开发android环境搭建_window

    golang开发android环境搭建介绍 一 安装依赖软件: git:版本管理 go:  go开发环境(版本>=1.5),可直接下载window版的go安装包. android studio: ...

  6. Windows下visual studio code搭建golang开发环境

    Windows下visual studio code搭建golang开发环境 序幕 其实环境搭建没什么难的,但是遇到一些问题,主要是有些网站资源访问不了(如:golang.org),导致一些包无法安装 ...

  7. linux golang开发环境配置(离线方式)

    <获取开发工具>     到https://www.golangtc.com/download 下载安装包, 根据自己的系统选择合适的开发包,这里选择go.1.9.2.linux-amd6 ...

  8. Linux下golang开发环境搭建

    对于golang开发来说,Windows下可以用vscode或者liteide都不错,但是Linux下的开发也就只有vim了,所以怎么搞笑的利用vim进行golang开发呢? 参考官方推荐的一个插件: ...

  9. window / Linux 下 Golang 开发环境的配置

    一直专注于使用python语言进行程序开发,但是却又一直被它的性能问题所困扰,直到遇到了天生支持高并发的Golang,这似乎也成了学习go语言最理所当然的理由.下面介绍下Go语言开发环境搭建的步骤: ...

  10. Golang开发环境搭建-Vim篇

    一.一个干净的环境 找个干净的基础环境,方便确认每个搭建步骤后的效果: Ubuntu 14.04 x86_64 vim version 7.4.52 go version go1.4beta1 lin ...

随机推荐

  1. k8s 深入篇———— docker 是什么[一]

    前言 简单的整理一下一些基本概念. 正文 简单运行一个容器: 创建一个容器: docker run -it busybox /bin/bash 然后看下进程: ps -ef 做了一个障眼法,使用的是p ...

  2. redis 简单整理——哨兵原理[三十一]

    前言 简单介绍一下哨兵的原理. 正文 一套合理的监控机制是Sentinel节点判定节点不可达的重要保证,Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控: 1)每隔10秒,每个 ...

  3. 如何使用Plotly和Dash进行数据可视化

    本文分享自华为云社区<从数据到部署使用Plotly和Dash实现数据可视化与生产环境部署>,作者: 柠檬味拥抱. 数据可视化是数据分析中至关重要的一环,它能够帮助我们更直观地理解数据并发现 ...

  4. @EnableDiscoveryClient 注解如何实现服务注册与发现

    @EnableDiscoveryClient 是如何实现服务注册的?我们首先需要了解 Spring-Cloud-Commons 这个模块,Spring-Cloud-Commons 是 Spring-C ...

  5. python pickle模块,打包创建的对象,做持久化

    pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. pickle.dump(obj, file[, protocol]) 序列化对象,并将结果数据流写入到文件对象中.参数pr ...

  6. Oracle nullif函数使用

    nullif函数使用 简单来说,就是表达式1的值和表达式2的值进行对比 可以使用''字符 select nullif('','1111') from dual 输出为空 不可以使用null字符 sel ...

  7. DataFunTalk:阿里建设一站式实时数仓的经验分享

    简介: 本文内容整理于阿里资深技术专家姜伟华在DataFunTalk上的演讲,为大家介绍阿里巴巴基于一站式实时数仓Hologres建设实时数仓的经验和解决方案. 导读:大数据计算正从规模化走向实时化, ...

  8. 淘宝推荐、视频搜索背后的检索技术竟是它!深度揭秘达摩院向量检索引擎Proxima

    简介: 淘宝搜索推荐.视频搜索的背后使用了什么样的检索技术?非结构化数据检索,向量检索,以及多模态检索,它们到底解决了什么问题?今天由阿里巴巴达摩院的科学家从业务问题出发,抽丝剥茧,深度揭秘达摩院内部 ...

  9. 阿里云EMR Remote Shuffle Service在小米的实践

    ​简介:阿里云EMR自2020年推出Remote Shuffle Service(RSS)以来,帮助了诸多客户解决Spark作业的性能.稳定性问题,并使得存算分离架构得以实施,与此同时RSS也在跟合作 ...

  10. WPF 触摸下如何给 StylusPointCollection 添加点

    本文告诉大家如何在触摸下给 WPF 的 StylusPointCollection 添加新的点 在自己默认创建的 StylusPointCollection 里面添加点是十分简单的,如以下代码,可以非 ...