node websocket socket.iohtml
咱们日常开发的大部分web页面都是主动‘拉’的形式,若是须要更新页面内容,则须要“刷新”一个,但Slack工具却能主动收到信息,好像服务端能主动给客户端推送信息,请研究一下这是怎么实现的。node
websocket是HTML5中新引进的一种 协议
,它是一种协议就像(HTTP,FTP在tcp/ip协议栈中属于应用层)而不是简单的一个函数。它自己及基于TCP协议的一种新的协议。git
websocket是基于web的实时性而产生的,说到这里就不得不要追溯一下web的历史了,在2005年(也就是ajax还没诞生)之前,咱们若是想要在一个页面显示显示不一样的内容,或者说页面内跳转,只能是经过点击而后路由跳转,在ajax诞生以后,网页开始变得动态了。可是全部的HTTP通讯还都是由客户端控制的,这就要须要长链接,按期轮询或者长轮询,来和服务器沟通来更新数据。github
优势:后端程序编写比较容易。
缺点:请求中有大半是无用,浪费带宽和服务器资源。
实例:适于小型应用。web
优势:在无消息的状况下不会频繁的请求,耗费资源小。
缺点:服务器hold链接会消耗资源,返回数据顺序无保证,难于管理维护。
实例:旧的 WebQQ、Hi网页版、Facebook IM。ajax
SSE,Comet,使用长连接进行通信。编程
优势:消息即时到达,不发无用请求;管理起来也相对方便。
缺点:服务器维护一个长链接会增长开销。
实例:Gmail聊天后端
优势:实现真正的即时通讯,而不是伪即时。
缺点:客户端必须安装Flash插件;非HTTP协议,没法自动穿越防火墙。
实例:网络互动游戏。设计模式
以上几种服务器“推”的技术中:长轮询和流控制其实都是基于长连接来实现的,也就是 http1.1
中所谓的 keep-alive
。在一个TCP链接上能够传送多个HTTP请求和响应,减小了创建和关闭链接的消耗和延迟。api
HTTP是无状态的,也就是说,浏览器和服务器每进行一次HTTP操做,就创建一次链接,但任务结束就中断链接。若是客户端浏览器访问的某个HTML或其余类型的Web页中包含有其余的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会创建一个HTTP会话
HTTP1.1和HTTP1.0相比较而言,最大的区别就是HTTP1.1默认支持持久链接(最新的 http1.0 能够显示的指定 keep-alive),但仍是无状态的,或者说是不能够信任的。
在向客户发送所请求文件的同时,服务器并无存储关于该客户的任何状态信息。即使某个客户在几秒钟内再次请求同一个对象,服务器也不会响应说:本身刚刚给它发送了这个对象。相反,服务器从新发送这个对象,由于它已经完全忘记早先作过什么。既然HTTP服务器不维护客户的状态信息,咱们因而 说HTTP是一个无状态的协议(stateless protocol)。
基于http协议的长链接减小了请求,减小了创建链接的时间,可是每次交互都是由客户端发起的,客户端发送消息,服务端才能返回客户端消息。由于客户端也不知道服务端何时会把结果准备好,因此客户端的不少请求是多余的,仅是维持一个心跳,浪费了带宽。
WebSocket 协议在2008年诞生,2011年成为国际标准。全部浏览器都已经支持了。WebSocket通讯协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。
关于HTML5的故事不少人都是知道的,w3c放弃了HTML,而后有一群人(也有说是这些人供职的公司,不过官方的文档上是说的我的)创立了WHATWG组织来推进HTML语言的继续发展,同时,他们还发展了不少关于Web的技术标准,这些标准不断地被官方所接受。WebSocket就属于WHATWG发布的Web Application的一部分(即HTML5)的产物。
它的最大特色就是,服务器能够主动向客户端推送信息,客户端也能够主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其中 Upgrade: websocket Connection: Upgrade
告诉服务器咱们发起的是一个 WebSocket
请求。Sec-WebSocket-Key
是一个 Base64encode
的值,这个是浏览器随机生成的,验证服务器是否是真的是Websocket助理。
而后,Sec_WebSocket-Protocol
是一个用户定义的字符串,用来区分同URL下,不一样的服务所须要的协议。
最后,Sec-WebSocket-Version
是告诉服务器所使用的WebsocketDraft(协议版本)。
详细接口文档: MDN WebSocket
建立对象:var ws = new WebSocket(url,name);
url为WebSocket服务器的地址,name为发起握手的协议名称,为可选择项。
发送文本消息:ws.send(msg);
msg为文本消息,对于其余类型的能够经过二进制形式发送。
接收消息:ws.onmessage = (function(){...})();
错误处理:ws.onerror = (function(){...})();
关闭链接:ws.close();
咱们借助这个测试接口 wss://echo.websocket.org
来作一个小demo。
公用html(下面的代码基本也是这个结构):
<h1>客户端简单例子</h1> <i>这里咱们走Kaazing WebSocket为咱们提供的接口,这个接口将完整返回咱们所发送的数据。</i> <p>状态:<strong id="state"></strong></p> <p>返回数据:<strong id="msg"></strong></p> <input id="sendText" type="text" name=""> <button id="sendBtn">发送</button> <button id="closeBtn">关闭</button>
JS:
var show = document.getElementById('state'), msg = document.getElementById('msg'), st = document.getElementById('sendText'), sb = document.getElementById('sendBtn'); if ("WebSocket" in window) { var ws = new WebSocket('wss://echo.websocket.org'); ws.onopen = function(e) { show.innerText = 'WebSocket链接成功~'; ws.send('Hello WebSockets!'); }; ws.onmessage = function(e) { msg.innerText = e.data; }; ws.onclose = function(e) { show.innerText = 'WebSocket链接关闭~'; } sb.addEventListener('click',function(){ ws.send(st.value); }) }else{ alert('你的浏览器不支持WebSocket'); }
nodejs-websocket是一个nodeJs的模块,咱们能够用它来轻易地为咱们以前的代码单独搭建一个WebSocket的nodeJs服务端。
yarn add nodejs-websocket
var ws = require("nodejs-websocket") // Scream server example: "hi" -> "HI!!!" var server = ws.createServer(function (conn) { console.log("New connection") conn.on("text", function (str) { console.log("Received "+str) conn.sendText(str.toUpperCase()+"!!!") }) conn.on("close", function (code, reason) { console.log("Connection closed") }) }).listen(8001)
在某种程度上,socket.io就是websocket,其实socket.io与websocket不是一回事,并且websocket能够说是socket.io的一个子集,socket.io的底层实现其实有5种方式,websocket只是其中一种,只不过在默认的状况下,咱们创建的socket.io链接,底层也是调用websocket的实例。当咱们io.connect()创建一个socket链接的时候,返回的是namespace实例,namespace实例中有个socket实例,当新建一个链接,或者发送一条消息的时候,namespace->socket->transport->websocket(xhrpolling...),其实发送一条消息真正的发送者仍是底层的websocket或是xhrpolling或其余的几种,而socket.io只是一个组织者,当咱们须要创建链接的时候,它本身会在其内部挑选一种链接方式,而后实现链接。
Socket.io都实现了Polling中的那些通讯机制呢?
应用层的协议,WebSocket在现代的软件开发中被愈来愈多的实践,和HTTP有一些类似的地方,并且有人也会把WebSocket和Socket混为一谈,那么他们之间到底有什么异同呢?
咱们先看两个协议的截图来领会下。
其实就像Java和JavaScript同样,WebSocket和Socket并无太大的关系。
Socket能够有不少意思,和IT较相关的本意大体是指在端到端的一个链接中,这两个端叫作Socket。对于IT从业者来讲,它每每指的是TCP/IP网络环境中的两个链接端,大多数的API提供者(如操做系统,JDK)每每会提供基于这种概念的接口,因此对于开发者来讲也每每是在说一种编程概念。同时,操做系统中进程间通讯也有Socket的概念,但这个Socket就不是基于网络传输层的协议了。
Socket 其实并非一个协议。它工做在 OSI 模型会话层(第5层),是为了方便你们直接使用更底层协议(通常是 TCP 或 UDP )而存在的一个抽象层。
Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来讲,一组简单的接口就是所有,让Socket去组织数据,以符合指定的协议。
主机 A 的应用程序要能和主机 B 的应用程序通讯,必须经过 Socket 创建链接,而创建 Socket 链接必须须要底层 TCP/IP 协议来创建 TCP 链接。创建 TCP 链接须要底层 IP 协议来寻址网络中的主机。咱们知道网络层使用的 IP 协议能够帮助咱们根据 IP 地址来找到目标主机,可是一台主机上可能运行着多个应用程序,如何才能与指定的应用程序通讯就要经过 TCP 或 UPD 的地址也就是端口号来指定。这样就能够经过一个 Socket 实例惟一表明一个主机上的一个应用程序的通讯链路了。
而 WebSocket 则不一样,它是一个完整的 应用层协议,包含一套标准的 API 。
因此,从使用上来讲,WebSocket 更易用,而 Socket 更灵活。
websocket api在浏览器端的普遍实现彷佛只是一个时间问题了, 值得注意的是服务器端没有标准的api, 各个实现都有本身的一套api, 而且tcp也没有相似的提案, 因此使用websocket开发服务器端有必定的风险.可能会被锁定在某个平台上或者未来被迫升级。
本文相关的Demo已经放在做者的Github上: 小楼兰的github