Go语言实现的WebSocket

作者:豌豆射手_BiuBiu 链接:https://www.jianshu.com/p/a5b187f7e669 來源:简书

  • 最终的效果如下

Web端上传的信息

Web端得到的打印的信息

服务端的代码的实现

服务端的信息

  • WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。WebSocket是HTML5的重要特性,它实现了基于浏览器的远程socket,它使浏览器和服务器可以进行全双工通信,许多浏览器Firefox、Google Chrome和Safari都已对此做了支持
  • WebSocket出现之前,为了实现即时通信,采用的技术都是“轮询”,即在特定的时间间隔内,由浏览器对服务器发出HTTP Request,服务器在收到请求后,返回最新的数据给浏览器刷新,“轮询”使得浏览器需要对服务器不断发出请求,这样会占用大量带宽。
  • 很多的游戏的服务都是采用的是Socket,因为HTTP协议相对而言比较耗费性能, 随着HTML5的发展,WebSocket也逐渐发展成为很多页游公司接下来开发的一些手段。
  • 安卓推送的原理: C2DM 推送 (Google) C2DM 推送简介 : 全称 Cloudto Device Messaging, Google 提供的 推送解决方案;
    • 运行方式 : 提供一个轻量级机制, 允许服务器通知应用程序, 主动与客户端进行数据交互, 处理消息排队, 并向运行于目标设备的应用程序分发消息;
    • 优点 : Google 提供的原生框架, 无需在应用中添加第三方代码 和 部署服务器端;
    • 缺点 : 1.该推送依赖 Google 服务器, 需要绑定 Google 帐号, 目前在中国 Google 被屏蔽, 无法使用; 2. 许多手机厂商去掉了软件中的该模块;
  • 极光推送的原理:因为IP v4 的 IP 量有限,运营商分配给手机终端的 IP 是运营商内网的 IP,手机要连接 Internet,就需要通过运营商的网关做一个网络地址转换Network Address Translation,NAT。简单的说运营商的网关需要维护一个外网 IP、端口到内网 IP、端口的对应关系,以确保内网的手机可以跟 Internet 的服务器通讯。
  • Android 平台上长连接的实现
    • Timer Android 的 Timer 类可以用来计划需要循环执行的任务,Timer 的问题是它需要用 WakeLock 让 CPU 保持唤醒状态,这样会大量消耗手机电量,大大减短手机待机时间。
    • AlarmManager 这篇文章有介绍怎么使用AlarmManager安卓网络和电量优化 AlarmManager 是 Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。 这意味着,如果我们用 AlarmManager 来定时执行任务,CPU 可以正常的休眠,只有在需要运行任务时醒来一段很短的时间。极光推送的 Android SDK 就是基于这种技术实现的。极光官方文档
  • WebSocket URL的起始输入是ws://或是wss://(在SSL上)。一个带有特定报头的HTTP握手被发送到了服务器端,接着在服务器端或是客户端就可以通过JavaScript来使用某种套接口(socket),这一套接口可被用来通过事件句柄异步地接收数据。

WebSocket 原理

  • WebSocket的协议:在第一次handshake通过以后,连接便建立成功,其后的通讯数据都是以”\x00″开头,以”\xFF”结尾。在客户端,这个是透明的,WebSocket组件会自动将原始数据“掐头去尾”。

request的信息.png

 1GET http://localhost:8080/shiming HTTP/1.1
 2Host: localhost:8080
 3Connection: Upgrade
 4Pragma: no-cache
 5Cache-Control: no-cache
 6Upgrade: websocket
 7Origin: file://
 8Sec-WebSocket-Version: 13
 9User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0
10Accept-Encoding: gzip, deflate, sdch, br
11Accept-Language: zh-CN,zh;q=0.8
12Cookie: _ga=GA1.1.27955907.1529919744
13Sec-WebSocket-Key: PCD+pA79juC6tlBK9zD3Vw==
14Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
  • Sec-WebSocket-Key这个是个随机的值,是一个经过base64编写后的数据Sec-WebSocket-Key: PCD+pA79juC6tlBK9zD3Vw==
  • 然后服务器收到这个请求之后把这个字符串连接上一个固定的字符串 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 为啥是这样的,我目前还不明白,仅仅是自己记录下而已。
  • 最终得到:
1PCD+pA79juC6tlBK9zD3Vw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
  • 对该字符使用shal 安全散列算法计算出二进制的值,然后用base64 对其进行编码,即可以得到握手的字符串: 8+5CLWTBYLARKoxBxS5uk6s6zZo= ,如下图所示

response信息.png

1HTTP/1.1 101 Switching Protocols
2Upgrade: websocket
3Connection: Upgrade
4Sec-WebSocket-Accept: 8+5CLWTBYLARKoxBxS5uk6s6zZo=
  • Sec-WebSocket-Accept作为响应头的值反馈给客户端。

Go语言实现Websocket

  • 由于Go语言标准包里面没有对WebSocket的支持,但是官方维护的go.net对这个有支持,所以可以获取
1go get golang.org/net/websocket
  • 但是有个小问题,当我 go get后,我在代码中导入包会报错,同时去掉x也不行,所以我在本地目录创建了一个x的目录,然后把net全部放进去了

注意问题.png

导包

  • html 代码
 1<html>
 2<head>
 3    <title>好好学习</title>
 4</head>
 5<body>
 6<script type="text/javascript">
 7    var sock = null;
 8    // var wsuri = "wss://127.0.0.1:8080"; //本地的地址 是可以改变的哦
 9     var wsuri = "ws://localhost:8080/shiming"; //本地的地址 是可以改变的哦
10
11
12    window.onload = function() {
13        //可以看到客户端JS,很容易的就通过WebSocket函数建立了一个与服务器的连接sock,当握手成功后,会触发WebScoket对象的onopen事件,告诉客户端连接已经成功建立。客户端一共绑定了四个事件。
14        console.log("开始了 onload");
15
16        sock = new WebSocket(wsuri);
17        //建立连接后触发
18        sock.onopen = function() {
19            console.log(" 建立连接后触发 connected to " + wsuri);
20        }
21        // 关闭连接时候触发
22        sock.onclose = function(e) {
23            console.log("关闭连接时候触发 connection closed (" + e.code + ")");
24        }
25        // 收到消息后触发
26        sock.onmessage = function(e) {
27            console.log("收到消息后触发 message received: " + e.data);
28        }
29        //发生错误的时候触发
30        sock.onerror=function (e) {
31            console.log("发生错误时候触发"+wsuri)
32        }
33    };
34     //如果sock被关闭掉了 这里 也会报错的啊
35    function send() {
36        var msg = document.getElementById('message').value;
37        sock.send(msg);
38    };
39</script>
40<h1>GoWebSocketDemo</h1>
41<form>
42    <p>
43        Message: <input id="message" type="text" value="你好啊  shiming 小哥哥  嘿嘿   ">
44    </p>
45</form>
46<button onclick="send();">给服务器发送消息</button>
47</body>
48</html>
  • go 代码
 1package main
 2
 3import (
 4    "fmt"
 5    "net/http"
 6    //草拟吗 自己创建的目录 哈哈哈哈哈    还好我比较聪明  要不然 就完蛋了  麻痹
 7    "golang.org/x/net/websocket"
 8    "log"
 9)
10
11func main() {
12    fmt.Println("Go语言标准包里面没有提供对WebSocket的支持,但是在由官方维护的go.net子包中有对这个的支持 go get golang.org/x/net/websocket")
13    //打印这个信息就,os.Exit(1)  退出程序
14    //log.Fatal("shiming")  todo  草拟吗 啊   看清楚啊   后面的域名的地址 有个老子的名字啊
15    http.Handle("/shiming",websocket.Handler(Echo))
16     if err:=http.ListenAndServe(":8080",nil);err!=nil{
17        log.Fatal(err)
18     }
19
20
21}
22
23func Echo(w *websocket.Conn)  {
24    var error error
25    for   {
26        var reply string
27        if  error= websocket.Message.Receive(w,&reply);error!=nil{
28            fmt.Println("不能够接受消息 error==",error)
29            break
30        }
31        fmt.Println("能够接受到消息了--- ",reply)
32        msg:="我已经收到消息 Received:"+reply
33        //  连接的话 只能是   string;类型的啊
34        fmt.Println("发给客户端的消息: "+msg)
35
36        if error = websocket.Message.Send(w, msg); error != nil {
37            fmt.Println("不能够发送消息 悲催哦")
38            break
39        }
40    }
41}
  • 说明一点:http.Handle("/shiming",websocket.Handler(funName)),如果在这里有路由的话,记得在 html中也要改成一样的, html中的代码 :var wsuri = "ws://localhost:8080/shiming"
  • x目录自己创建一个,把net包剪切进去就可以

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

Golang语言社区

ID:Golangweb

www.bytedancing.com

游戏服务器架构丨分布式技术丨大数据丨游戏算法学习

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2018-09-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张戈的专栏

安装完Win7之后推荐做的一些设置

前言:不知道写什么,就总结一下我个人安装完成 windows7 之后要做的一些设置吧!以下全文均为个人回忆总结,文章也很冗长,难免有纰漏或者不符合你个人习惯的内...

1.1K140
来自专栏kl的专栏

记阿里Druid数据连接池引发的线上血案

事件起因:项目使用了activiti工作流,系统是由老的spring mvc项目改造成的spring boot项目,数据库链接池从dbcp切换到druid,新系...

1.1K70
来自专栏数据和云

如何优雅地添加MGR节点?

MySQL Group Replication(简称MGR)是MySQL官方于2016年12月份推出的一个全新的高可用与高扩展的解决方案。MGR提供了高可用、高...

47890
来自专栏杨逸轩 ' sBlog

利用微博当图床-php语言实现

75360
来自专栏FreeBuf

Kali 2.0 安装与使用指南

关于kali使用前的一些配置,网上有很多版本,但是几乎都很雷同,或者是不全,或者是根本就没有测试过,或者是有的方法是错的(换句话说是版本变化的差异),因此让很多...

1.2K50
来自专栏北京马哥教育

Linux之HA高可用集群的基础概念总结

HA(High Availability)高可用集群,其特点为根据实际需求为前端Diretor,后端RS-server,数据库服务器,共享存储等集群节点做一个...

45960
来自专栏IMWeb前端团队

利用whistle调试WebSocket和Socket请求

whistle v1.6.0 (Github地址:https://github.com/avwo/whistle) 开始支持WebSocket和一般Socket...

55800
来自专栏Python与爬虫

websocket与爬虫

背景 写爬虫的目的应该就是为了拿到数据,或者说模拟某种操作 如果他使用的是http(s) 协议来传输数据的,那么我们就模拟http协议来发送数据 如果它使用的是...

676120
来自专栏nnngu

看完让你彻底理解 WebSocket 原理,附完整的实战代码(包含前端和后端)

最近有同学问我有没有做过在线咨询功能。同时,公司也刚好让我接手一个 IM 项目。所以今天抽时间记录一下最近学习的内容。本文主要剖析了 WebSocket 的原理...

16320
来自专栏Java技术分享

Shard 分片集群

简述 为何要分片 减少单机请求数,降低单机负载,提高总负载 减少单机的存储空间,提高总存空间。 常见的mongodb sharding 服务器架构 要构建一...

23490

扫码关注云+社区

领取腾讯云代金券