经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Go语言 » 查看文章
golang开发 gorilla websocket的使用
来源:cnblogs  作者:飞翔码农  时间:2024/5/31 9:21:43  对本文有异议

很多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

  1. recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889
  2. recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605
  3. recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325
  4. recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866
  5. recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108
  6. recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310
  7. recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266

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

  1. connecting to ws://localhost:8080/echo
  2. recv: 2024-04-16 15:09:45.805438 +0800 CST m=+1.007536889
  3. recv: 2024-04-16 15:09:46.805425 +0800 CST m=+2.007517605
  4. recv: 2024-04-16 15:09:47.806274 +0800 CST m=+3.008359325
  5. recv: 2024-04-16 15:09:48.80495 +0800 CST m=+4.007028866
  6. recv: 2024-04-16 15:09:49.805743 +0800 CST m=+5.007816108
  7. recv: 2024-04-16 15:09:50.806087 +0800 CST m=+6.008153310
  8. recv: 2024-04-16 15:09:51.805348 +0800 CST m=+7.007407266

我们看看这个简单的例子。
client.go

  1. go func() {
  2. defer close(done)
  3. for {
  4. _, message, err := c.ReadMessage()
  5. if err != nil {
  6. log.Println("read:", err)
  7. return
  8. }
  9. log.Printf("recv: %s", message)
  10. }
  11. }()
  12. ticker := time.NewTicker(time.Second)
  13. defer ticker.Stop()
  14. for {
  15. select {
  16. case <-done:
  17. return
  18. case t := <-ticker.C:
  19. err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
  20. if err != nil {
  21. log.Println("write:", err)
  22. return
  23. }
  24. case <-interrupt:
  25. log.Println("interrupt")
  26. // Cleanly close the connection by sending a close message and then
  27. // waiting (with timeout) for the server to close the connection.
  28. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
  29. if err != nil {
  30. log.Println("write close:", err)
  31. return
  32. }
  33. select {
  34. case <-done:
  35. case <-time.After(time.Second):
  36. }
  37. return
  38. }
  39. }

go func() 的 c.ReadMessage 不停的从socket里面读取数据并且打印。
for 循环不停的从1秒的定时器里面读取时间,写到socket

server.go

  1. for {
  2. mt, message, err := c.ReadMessage()
  3. if err != nil {
  4. log.Println("read:", err)
  5. break
  6. }
  7. log.Printf("recv: %s", message)
  8. err = c.WriteMessage(mt, message)
  9. if err != nil {
  10. log.Println("write:", err)
  11. break
  12. }
  13. }

for c.ReadMessage 循环不停的从 socket读取数据,把数据打印之后,又写给客户端。
这是大致的websocket 客户端与服务端通信的简单例子。

改成自定义的协议

我们使用二进制数据流,自定义的协议是这样的,
先是无符号的 uint 占4个字节,表示行为逻辑,比如111-获取信息, 110- 加好友等等
后面是具体的数据,跟HTTP请求的GET或者POST参数类似,具体数据格式定义好就行,比如可以使用JSON数据、可以使用RPC定义好的数据格式

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

  1. for {
  2. select {
  3. case <-done:
  4. return
  5. case <-ticker.C:
  6. buf := bytes.NewBuffer([]byte{})
  7. binary.Write(buf, binary.BigEndian, uint32(110))
  8. binary.Write(buf, binary.BigEndian, []byte("我们都好"))
  9. err := c.WriteMessage(websocket.BinaryMessage, buf.Bytes())
  10. if err != nil {
  11. log.Println("write:", err)
  12. return
  13. }
  14. case <-interrupt:
  15. log.Println("interrupt")
  16. // Cleanly close the connection by sending a close message and then
  17. // waiting (with timeout) for the server to close the connection.
  18. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
  19. if err != nil {
  20. log.Println("write close:", err)
  21. return
  22. }
  23. select {
  24. case <-done:
  25. case <-time.After(time.Second):
  26. }
  27. return
  28. }
  29. }

主要是这个

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

创建一个bytes Buffer
写入一个uint32,占4个字节,表示行为逻辑
写入行为逻辑具体的数据
以上采用大端通信

修改之后的 server.go

  1. for {
  2. mt, message, err := c.ReadMessage()
  3. if err != nil {
  4. log.Println("read:", err)
  5. break
  6. }
  7. log.Println("messagetype:%d", mt)
  8. log.Println("messagelen:%d", len(message))
  9. log.Println("messagetype:%d", binary.BigEndian.Uint32(message[0:4]))
  10. log.Println("recv: %s", string(message[4:]))
  11. err = c.WriteMessage(mt, message)
  12. if err != nil {
  13. log.Println("write:", err)
  14. break
  15. }
  16. }

mt websocket 类型
TextMessage = 1 文本类型传传输
BinaryMessage = 2 字节类型传输

从socket里面获取到message之后
先取前4个字节,表示逻辑行为
再取剩余的字节,表示行为逻辑需要的参数

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

  1. go run client.go
  2. connecting to ws://localhost:8080/echo
  3. recv: n我们都好
  4. recv: n我们都好
  5. go run server.go
  6. messagetype:%d 2
  7. messagelen:%d 16
  8. messagetype:%d 110
  9. recv: %s 我们都好

messagetype=2表示二进制通信
message长度是16,前四个字节是无符号整形,四个汉字占12个字节,一共16个字节,无符号uint是110表示加好友。

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

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

生产的部署

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

  1. map $http_upgrade $connection_upgrade {
  2. default upgrade;
  3. '' close;
  4. }
  5. server {
  6. listen 80;
  7. location /serv/ {
  8. proxy_set_header Upgrade $http_upgrade;
  9. proxy_set_header Connection $connection_upgrade;
  10. proxy_connect_timeout 3;
  11. proxy_redirect off;
  12. proxy_read_timeout 3600;
  13. proxy_send_timeout 3600;
  14. proxy_pass http://push_web/serv/;
  15. }
  16. }

原文链接:https://www.cnblogs.com/feixiangmanon/p/18222685

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号