分享

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

 gotot5 2016-10-11




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

  • 关于新的HTTP规范

  • WebSocket和Socket的区别

  • WebSocket中数据帧的格式

  • WebSocket的实现:socket.IO

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


 1   关于新的HTTP规范


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

  1. Upgrade头域功能的扩展

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


  2. Uri的格式

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

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


 2   WebSocket和Socket的关系


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

  • 命名方面,Socket是一个深入人心的概念,WebSocket借用了这一概念;

  • 使用方面,完全两个东西。


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


 3   WebSocket中数据帧的格式


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


 4   WebSocket的实现:socket.IO


socket.IO是一个基于node的实时通信引擎(FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE),第一次看到这个框架时,就想到它的底层应该就是WebSocket吧,实时全双工通信,不就是WebSocket的设计目标吗?于是开始对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这种妥协的方法不失为一个向下兼容的好办法。


WebSocket连接无法正常建立


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


WebSocket连接正常建立


ws

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


一件有趣的小事

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


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


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


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

  • 鉴权

    发布消息的人需要登录之后才能进行操作。

  • 发布消息

    直播的播主进行直播,播主的客户端与服务器建立WebSocket连接,在发送消息的同时也作为一个接收消息的客户端。

  • 接收消息

    所有打开直播页面的客户端都与服务器建立一个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)


 6   后记


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


作者:奎奎

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多