看这篇文章的时候,千万不要害怕代码,重要的核心的都加注释了,原理很简单!!祝阅读顺利

当学习一门新的语言的时候,总是喜欢先建立一个Demo项目,通过构建一个基本的项目,来了解语言的特点。

对于web的交互,以前常用的技术主要是Ajax、Form表单提交这类,如果要做长连接,可以使用Websocket

关于websocket和socket其实是两个东西,如果要比较的话,应该是拿websocket和http 来比较。

websocket 发送json

websocket发送json这是一种常规的方式

值得一提的是,Vue框架中使用axios发送POST请求的时候,默认Content-Type是application/json,所以在后端接受的时候,要做流处理。

比如像PHP的话,要用php://input,如果是go,那么就要使用下面的代码,来获取请求body的全部内容,然后使用json.Unmarshal来解析

我们继续来看Vue的websocket部分

上面这段代码,是定义在Vue的组件中的。其实核心就是通过mounted组件挂载完成之后,来调用new WebSocket创建连接,并且注册onOpen,onMessage,onClose事件。

通过websocket来发送json,实际上是传递了一个json的字符串,对于基于golang的后端,我们同样需要搭建websocket 服务端来接收消息。

golang的websocket服务

websocket是在http协议上进行的升级。

这里我们使用的是websocket包

对于main函数,我们构建如下

echo 函数如下定义,不要害怕这么长一段代码,其实核心很简单

  1. 我们首先建立结构体
  1. 下面是主要的echo函数,完成的就是升级http,监听某个链接的请求,并且进行回复

这里面用到的方法主要是

  • upgrader.CheckOrigin 解决跨域问题
  • upgrader.Upgrade()
  • c.ReadMessage()
  • c.WriteMessage()

注意上面c.WriteMessage(mt,b) 的第一个参数是MessageType类型,有两个值分别是代表 二进制、文本

websocket结合protobuf

在上面的例子当中,我们看到通过websocket来建立长连接,并且与go的websocket服务进行通信

使用websocket来避免轮询已经是一个减轻服务器请求压力的办法了,那么我们能否在传输协议上在做一些改变,来减小传输的包体大小。

使用protobuf

关于protobuf,是一种编码协议,可以想象一下json、xml。

protoc是proto文件的编译器,proto-gen-go是protoc的插件,可以根据proto文件,编译成go文件。

google-protobuf 现在也支持了生成 js文件。

用protobuf的还有一个好处是指,如果我在go的服务端,定义好了Request的包体内容,以及Response的包体内容,那么生成go文件后,也可以同时生成js文件

这样双方就可以按照同样的参数模式来进行开发,就等于proto文件,相当于接口文档了

那我们先生成一个proto文件,比如说websocket要发请求,goserver要返回内容,那就涉及了两个消息结构的定义

然后使用protoc来生成文件go/js

proto go文件的使用

先引入go的proto文件

然后再代码中获取到websocket的消息后,进行proto解析,非常简单~~~~

proto js文件使用

proto的js文件,需要配合google-protobuf.js一起使用,根据官网文档来讲,如果要在浏览器中使用,需要用browserify进行打包。

在Vue的组件中,引入包

下面我们来看websocket结合protobuf,与传统的json有什么不同,同样不要害怕这么一大段代码,我们主要看method部分

只看上面注释的部分即可,其实分为两部分

  1. 按照约定的消息结构,set数据
  2. 按照约定的消息结构,get数据

注意:

  • proto.ChatResponse.deserializeBinary 是一个静态方法,不需要New
  • 一定要修改为arraybuffer,二进制数组

    1
    ws.binaryType = 'arraybuffer';

通过上面的流程,我们已经基本了解了protobuf在websocket中的配合使用,除此之外还有一个protobuf.js 也很火,但是没有做特别的研究,比较喜欢官方的。

广播boardcast

但是这里有个细节问题,如果要建立通信,一般上来讲,我们不会直接将信息返回回去。因为websocket是全双工通信,不像http一样请求一次、返回一次、close。

如果我们要用websocket,第一个反应是长连接,搞个聊天室实时聊天。那么下面我们来实现一个聊天能力。

那么聊天能力,其实有一个特点就是广播,一个人说话,所有人都能收到。这样特别有意思,很久以前用ajax来做的话,还需要把数据存起来,然后每次再轮询读取输出给前端。现在都不用存到数据库里了。

核心:

  1. 广播实际上就是把消息广播给所有与服务器建立连接的客户端

看下实现

先建立一个map,用来储存客户端连接,在建立个消息缓冲通道

每次新建连接之后,都会将链接保存到client当中,进行缓存。

proto解析的部分已经讲过了,这里将解析的内容写入到messages通道里面。

下面就是核心的boardcast方法

上面的boardcast方法,要交给协程goroutine处理,不然for range messages 会阻塞,所以在main方法中使用协程

小结一下

对于创建websocket和protobuf的聊天能力来说有如下的流程

  1. 双方要实现websocket通信
  2. 约定proto消息协议,生成go和js两个版本
  3. 使用goroutine协程,来进行广播

其中上面的例子,并没有在client退出的时候,从clients中将链接删除,实际上可以用下面的形式,来删除,并且conn.close关闭连接。

希望上面的内容,对大家有所帮助。详细问题可以留言讨论