刨根问底 HTTP 和 WebSocket 协议 (三)

上篇文章发出来后,有人留言说到HTTP新版的RFC的问题,WebSocket和Socket的区别。本文将先回答这两个问题,然后继续展开WebSocket。在这篇文章将看到:

  1. 关于新的HTTP规范
  2. WebSocket和Socket的区别
  3. WebSocket中数据帧的格式
  4. WebSocket的实现:socket.IO
  5. 使用socket.IO实现一个在线直播系统

关于新的HTTP规范

HTTP 1.1在2014年(15年后)被更新为6个单独的「协议说明」,如果去读这6个文档,又是很大的工作量,庆幸有很多文章总结了它们相对于RFC2616的不同之处,RFC7230中也列举了这些feature,所以只是大致把这个看了看。对于这个系列有影响的可能有这两点:

  1. Upgrade头域功能的扩展
    Upgrade是HTTP中用来进行协议升级的头域,在扩展的协议内容中,客户端发起的协议转换的方式更多,同时服务器也可以选择不接受客户端的协议升级请求;服务端也可以发起协议升级。

  2. Uri的格式
    #fragment的引入,现在越来越多的人愿意使用fragment来标识网站中的位置了。

完整的变化列表可以在这里找到。这次变化可以算是一个补丁版,把原来漏掉的小东西补上,版本号无变化。

WebSocket和Socket的关系

关于这两者的区别,我写了一篇专门的文章来讨论,可以在WebSocket和Socket的区别看到,简短的答案也放在这里,如果你不想去看另一篇的话。

  • 命名方面,Socket是一个深入人心的概念,WebSocket借用了这一概念;
  • 使用方面,完全两个东西。

可以把WebSocket想象成HTTP,想一想HTTP和Socket什么关系,WebSocket和Socket就是什么关系。

WebSocket中数据帧的格式

本文是此系列的最后一篇了,可能是因为懒,很多想写的东西最终都放弃了。关于WebSocket的帧传输这里就不做详细的讲解了,之前的文章试图把很多细节都展开,但发现那样最后只是变成了规则的罗列,如果有兴趣,可以去这里看文档。

WebSocket的实现:socket.IO

socket.IO是一个基于node的实时通信引擎(FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE),第一次看到这个框架时,就想到它的底层应该就是WebSocket吧,实时全双工通信,不就是WebSocket的设计目标吗?于是开始对WebSocket底层的实现进行简单的探索。

《刨根问底 HTTP 和 WebSocket 协议 (三)》

socket.IO主页

socket.IO的底层引擎是engine.io,engine.io的实现中使用了HTTP和WebSocket两种方式来构建自己的服务端,如果客户端不支持WebSocket协议,则使用轮询的方式来实现实时传输,如果客户端支持WebSocket协议,则使用另一个模块ws,ws是一个优秀的WebSocket的JS实现,在ws的README中他们自称为「可能是node平台上最快的WebSocket实现」。

对于普通产品的开发,我们可能不可避免的要照顾到那些从不支持WebSocket的客户端(一般情况下是浏览器)发出的请求,或者有的服务器中不支持部署WebSocket协议的服务端,所以socket.IO这种妥协的方法不失为一个向下兼容的好办法。

《刨根问底 HTTP 和 WebSocket 协议 (三)》

WebSocket连接无法正常建立

如果可以正常建立连接,则会停掉轮询的方式,使用WebSocket进行接下来的连接。

《刨根问底 HTTP 和 WebSocket 协议 (三)》

WebSocket连接正常建立

ws

socket.IO在JS领域算是大名鼎鼎了,截止到今天socket.IO在github上的star数量是27543,而作为socket.IO的核心模块,ws在github上的star数量却只有4005。

一件有趣的小事

ws的源码中可以搜到hixie这个单词,在上一篇关于WebSocket名字由来的文章中介绍过,这个人是WebSocket的命名者。

使用socket.IO实现一个在线直播系统

前段时间当时的老板要求做一个「简单的微信上的文字直播程序」,一接到这个需求,我想到的就是koa + WebSocket + mongoDB,不得不说,基于node的服务端开发极大的拉低了开发一个服务的门槛,尤其是ES6之后,感觉JS这个以前看起来很随意的语言变得愈加性感起来了 。语法越来越现代化,性能越来越好,而随着npm上的模块越来越多,开发一个业务系统变得空前的简单。

书归正传,经过分析之后,一个「简单的微信上的文字直播程序」大约有3个功能:

  • 鉴权
    发布消息的人需要登录之后才能进行操作。
  • 发布消息
    直播的播主进行直播,播主的客户端与服务器建立WebSocket连接,在发送消息的同时也作为一个接收消息的客户端。
  • 接收消息
    所有打开直播页面的客户端都与服务器建立一个WebSocket连接,第一次进入时拉取部分历史消息,之后每条播主的消息都会同步推送到客户端。

《刨根问底 HTTP 和 WebSocket 协议 (三)》

直播系统时序图

由于时间仓促,并没有严格保证代码质量,所以就不在这里贴太多的代码了,在这次实现中并没有直接使用socket.IO,而是使用了一个加壳的版本koa-socket,这个库已经很久没有更新了,它接受的函数并不是generator,所以在操作数据库时遇到了一些问题。其中处理发布消息的函数如下:

    controllers/socket.js
    exports.postedHandler = ( ctx, data ) => {
        const createdAt = new Date();
        let newPost = {content: data.content, createdAt: createdAt};
        if (data.image) {
            newPost.image = data.image;
        }
        newPost.date = moment(createdAt).format("HH:mm");
        Posts.insert(newPost);
        if (!app) {
            app = require('../app')
        }
        app.io.broadcast('posts', [newPost] )
    }

    app.js
    const IO = require( 'koa-socket' )
    ...
    /**some other code**/
    ...
    const io = new IO()
    io.attach( app )
    io.on('post', socket.postedHandler)

后记

最近由于各种各样的原因,原定的计划严重delay了。关于帧传输的一节本来设计了很多,可是写出来就变得索然无味了;关于在线直播系统的介绍,本以为可以写很多,但是写时才发现除了代码并没有什么好共享的。无论如何都算是给这个系列结了个尾,就像那句歌词,every new beginning comes from some other beginning’s end.

    原文作者:HTTP
    原文地址: https://juejin.im/entry/57ec9ef9bf22ec00643e4f01
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞