WebSocket 是什么原理?为什么可以实现持久连接?

原创
2016-06-07 08:41:37 1902浏览
WebSocket是HTML5出的东西 也就是说HTTP协议没有变化 但HTTP是不支持持久连接的(长连接,循环连接的不算)
或者说WebSocket干脆就不是基于HTTP来执行的。但是。。。说不通啊。。。

他是怎么实现的呢??为什么可以实现持久连接????
-----------------------------
【【【【【【【【【【【【【【补充】】】】】】】】】】:::::
既然WebSocket和HTTP是两个协议 为什么要在HTML5才支持
又如果说HTML5 出来以后可以用WebSocket了 就说明WebSocket是本来就有点东西只是HTML4不支持而已 http4时代 如何使用WebSocket呢?? 谢谢

回复内容:

额。。最高票答案没答到点子上,最后怎么跑到Nodejs上去了。。Websocket只是协议而已。。
我一个个来回答吧

一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)
首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充可以通过这样一张图理解
有交集,但是并不是全部。
另外Html5是指的一系列新的API,或者说新规范,新技术。Http协议本身只有1.0和1.1,而且跟Html本身没有直接关系。。
通俗来说,你可以用HTTP协议传输非Html数据,就是这样=。=
再简单来说,层级不一样

二、Websocket是什么样的协议,具体有什么优点
首先,Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
简单的举个例子吧,用目前应用比较广泛的PHP生命周期来解释。
1) HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么HTTP1.0,这次HTTP请求就结束了。
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response , 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。

教练,你BB了这么多,跟Websocket有什么关系呢?
_(:з」∠)_好吧,我正准备说Websocket呢。。
首先Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手。
在握手阶段是一样的
-------以下涉及专业技术内容,不想看的可以跳过lol:,或者只看加黑内容--------
首先我们来看个典型的Websocket握手(借用Wikipedia的。。)
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
你可以把 WebSocket 看成是 HTTP 协议为了支持长连接所打的一个大补丁,它和 HTTP 有一些共性,是为了解决 HTTP 本身无法解决的某些问题而做出的一个改良设计。在以前 HTTP 协议中所谓的 keep-alive connection 是指在一次 TCP 连接中完成多个 HTTP 请求,但是对每个请求仍然要单独发 header;所谓的 polling 是指从客户端(一般就是浏览器)不断主动的向服务器发 HTTP 请求查询是否有新数据。这两种模式有一个共同的缺点,就是除了真正的数据部分外,服务器和客户端还要大量交换 HTTP header,信息交换效率很低。它们建立的“长连接”都是伪.长连接,只不过好处是不需要对现有的 HTTP server 和浏览器架构做修改就能实现。

WebSocket 解决的第一个问题是,通过第一个 HTTP request 建立了 TCP 连接之后,之后的交换数据都不需要再发 HTTP request了,使得这个长连接变成了一个真.长连接。但是不需要发送 HTTP header就能交换数据显然和原有的 HTTP 协议是有区别的,所以它需要对服务器和客户端都进行升级才能实现。在此基础上 WebSocket 还是一个双通道的连接,在同一个 TCP 连接上既可以发也可以收信息。此外还有 multiplexing 功能,几个不同的 URI 可以复用同一个 WebSocket 连接。这些都是原来的 HTTP 不能做到的。

另外说一点技术细节,因为看到有人提问 WebSocket 可能进入某种半死不活的状态。这实际上也是原有网络世界的一些缺陷性设计。上面所说的 WebSocket 真.长连接虽然解决了服务器和客户端两边的问题,但坑爹的是网络应用除了服务器和客户端之外,另一个巨大的存在是中间的网络链路。一个 HTTP/WebSocket 连接往往要经过无数的路由,防火墙。你以为你的数据是在一个“连接”中发送的,实际上它要跨越千山万水,经过无数次转发,过滤,才能最终抵达终点。在这过程中,中间节点的处理方法很可能会让你意想不到。

比如说,这些坑爹的中间节点可能会认为一份连接在一段时间内没有数据发送就等于失效,它们会自作主张的切断这些连接。在这种情况下,不论服务器还是客户端都不会收到任何提示,它们只会一厢情愿的以为彼此间的红线还在,徒劳地一边又一边地发送抵达不了彼岸的信息。而计算机网络协议栈的实现中又会有一层套一层的缓存,除非填满这些缓存,你的程序根本不会发现任何错误。这样,本来一个美好的 WebSocket 长连接,就可能在毫不知情的情况下进入了半死不活状态。

而解决方案,WebSocket 的设计者们也早已想过。就是让服务器和客户端能够发送 Ping/Pong Frame(RFC 6455 - The WebSocket Protocol)。这种 Frame 是一种特殊的数据包,它只包含一些元数据而不需要真正的 Data Payload,可以在不影响 Application 的情况下维持住中间网络的连接状态。 WebSocket 是一种协议,基于 TCP 协议;HTTP 也是一种协议,基于 TCP 协议。
连接要保持还是关闭是由你服务器应用来控制的。

WebSocket 协议和 HTTP 协议是两种不同的东西,它们扯上关系是只是因为:
客户端开始建立 WebSocket 连接时要发送一个 header 标记了 Upgrade 的 HTTP 请求,表示请求协议升级。
所以服务器端做出响应的简便方法是,直接在现有的 HTTP 服务器软件和现有的端口上实现 WebSocket 协议,重用现有代码(比如解析和认证这个 HTTP 请求。如果在 TCP 协议上实现,这两个功能就要重新实现),然后再回一个状态码为 101 的 HTTP 响应完成握手,再往后发送数据时就没 HTTP 的事了。

=====
看了补充,问题已经越来越奇怪了,变成了历史问题。这种概念上的问题多看点书很容易解决。
互联网一共才十几年历史,而 WebSocket 从提议变成推荐标准就需要几年,因为中间要经过大量的安全验证和实验。
Web 1 的时代人们访问 Web 页面是即停即走。Web 2 之后单个页面停留时间越来越长,页面功能越来越丰富——这时有了 RIA 的概念,改变了客户端的编程模型——更甚至许多实时应用根本不用离开页面,比如聊天、游戏应用。
客户端浏览器决定了客户端编程语言的能拥有的功能,以前如何做那些交互性很高的应用呢?
一些技术有 XHR,iframe, 实时性要求非常高的就只能用第三方插件,比如 Flash 或 Silverlight。
但 XHR 和 iframe 存在一些根本避免不了问题:1)每次交互就需要两个 HTTP 请求 2)即使单个 HTTP 请求也要传送很多字节(header 笨重)3)客户端不知道消息何时能够到达,只能轮询。服务器肯定会表示压力很大!
插件则需要额外安装,还有安全性问题和移动设备根本不能被支持的问题。
有了需要之后才有了解决方案—— WebSocket 就是这种灵丹妙药,看看主要特性:实时交互、服务器能够主动推送内容、只需要建立一次连接、快速(延迟小,每条消息可以小到两个字节)、开发者友好(接口简单,并是熟悉的事件模型)等等。
所以,HTML 4 选择权很小,是否要支持 WebSocket 依据需求和环境而定;而选择 HTML 5 的话,有了 socket 通信和图形编程的能力,能够开发出什么精彩应用只取决于你的想象力。

PS:如果要找现成方案,这个 Wiki 上有很多:github.com/Modernizr/Mo HTML5 是一个很宽广的概念,是对大量新 API 的总称。不存在 HTTP5 的概念,HTTP 最高的版本号是 1.1。简单来说,你可以完全抛开 HTML5 和 HTML4 的概念,只考虑浏览器要么支持 WebSocket,要么不支持。

WebSocket 跟其他 API 比较不一样的是,它不仅仅依赖于浏览器支持,同时要求服务器和代理(假若需要经过代理的话)支持。WebSocket 本质上跟 HTTP 完全不一样,只不过为了兼容性,WebSocket 的握手是以 HTTP 的形式发起的,如果服务器或者代理不支持 WebSocket,它们会把这当做一个不认识的 HTTP 请求从而优雅地拒绝掉。

如果你真的很想知道这个协议具体是如何操作的,建议还是去看 RFC:tools.ietf.org/html/rfc websocket的实现已经有朋友提到了基于HTTP来发起,我这里不讨论太多实现,而是主要回答一下题主补充的问题:“【【【【【【【【【【【【【【补充】】】】】】】】】】:::::
既然WebSocket和HTTP是两个协议 为什么要在HTML5才支持
又如果说HTML5 出来以后可以用WebSocket了 就说明WebSocket是本来就有点东西只是HTML4不支持而已 http4时代 如何使用WebSocket呢?? 谢谢”

websocket是随着WWW的发展,应用场景越来越复杂而提出的,针对浏览器和web服务器之间双向持续通信而设计,而且优雅地兼容HTTP(我猜想:同时因为建立在HTTP上,也可以利用好HTTP原有的基础比如basic认证)。它和HTML5不是非得扯到一起,但是刚好是同时期,而且HTML5也刚好需要“socket”功能,因此顺理成章成为一部分。

而 websocket 的使用,更多的是“脚本”层面的事情,比如在javascript(不是非得javascript,但是javascript已经成为和浏览器交互的事实标准)中创建Websocket对象以便操作浏览器的websocket功能(这个功能便是浏览器根据HTML5草案实现出来的,参考草案的interface WebSocket部分定义),然后注册onopen/onmessage等回调接口,有数据或者状态变更之类的时机你就可以做相应的处理了。而这部分刚好在旧的标准没定义,浏览器也没有这样的功能,因此遵循HTML4编写的页面不会用到这些功能。 简单说,没错,WebSocket不是HTTP协议,HTTP只负责建立WebSocket连接。 "或者说WebSocket干脆就不是基于HTTP来执行的",这句是对的,WebSocket 和 HTTP 都是基于 TCP 的,TCP是传输层协议, WebSocket 和 HTTP是应用层协议,就是因为HTTP不能满足特定的需求才被设计出来的,所以会支持你说的那些特性。

websocket约定了一个通信的规范,通过一个握手的机制,客户端和服务器之间能建立一个类似tcp的连接,从而方便它们之间的通信。在websocket出现之前,web交互一般是基于http协议的短连接或者长连接。websocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法:ws://**。websocket协议本质上是一个基于tcp的协议。分析HTML5中WebSocket的原理

是服务器实现的。

客户端通过html5与服务器交互。http是不持续连接的,而websocket是。必须服务器支持websocket协议,才有效。对于不支持websocket服务的服务器,你客户端怎么写代码都没用。

web服务器必须支持websocket协议。我想这可以简单的回答题主的问题。

Web领域的实时推送技术,也被称作Realtime技术。这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新。它有着广泛的应用场景,比如在线聊天室、在线客服系统、评论系统、WebIM等。



WebSocket简介

谈到Web实时推送,就不得不说WebSocket。在WebSocket出现之前,很多网站为了实现实时推送技术,通常采用的方案是轮询(Polling)和Comet技术,Comet又可细分为两种实现方式,一种是长轮询机制,一种称为流技术,这两种方式实际上是对轮询技术的改进,这些方案带来很明显的缺点,需要由浏览器对服务器发出HTTP request,大量消耗服务器带宽和资源。面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并实现真正意义上的实时推送。


WebSocket协议本质上是一个基于TCP的协议,它由通信协议和编程API组成,WebSocket能够在浏览器和服务器之间建立双向连接,以基于事件的方式,赋予浏览器实时通信能力。既然是双向通信,就意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP的请求和响应。


为了建立一个WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的HTTP请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的WebSocket连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。


一个典型WebSocket客户端请求头:


前面讲到WebSocket是HTML5中新增的一种通信协议,这意味着一部分老版本浏览器(主要是IE10以下版本)并不具备这个功能, 通过百度统计的公开数据显示,IE8目前仍以33%的市场份额占据榜首,好在chrome浏览器市场份额逐年上升,现在以超过26%的市场份额位居第二,同时微软前不久宣布停止对IE6的技术支持并提示用户更新到新版本浏览器,这个曾经让无数前端工程师为之头疼的浏览器有望退出历史舞台,再加上几乎所有的智能手机浏览器都支持HTML5,所以使得WebSocket的实战意义大增,但是无论如何,我们实际的项目中,仍然要考虑低版本浏览器的兼容方案:在支持WebSocket的浏览器中采用新技术,而在不支持WebSocket的浏览器里启用Comet来接收发送消息。


WebSocket实战

本文将以多人在线聊天应用作为实例场景,我们先来确定这个聊天应用的基本需求。


需求分析

1、兼容不支持WebSocket的低版本浏览器。
2、允许客户端有相同的用户名。
3、进入聊天室后可以看到当前在线的用户和在线人数。
4、用户上线或退出,所有在线的客户端应该实时更新。
5、用户发送消息,所有客户端实时收取。


在实际的开发过程中,为了使用WebSocket接口构建Web应用,我们首先需要构建一个实现了 WebSocket规范的服务端,服务端的实现不受平台和开发语言的限制,只需要遵从WebSocket规范即可,目前已经出现了一些比较成熟的WebSocket服务端实现,比如本文使用的Node.js+Socket.IO。为什么选用这个方案呢?先来简单介绍下他们两。


Node.js

Node.js采用C++语言编写而成,它不是Javascript应用,而是一个Javascript的运行环境,据Node.js创始人Ryan Dahl回忆,他最初希望采用Ruby来写Node.js,但是后来发现Ruby虚拟机的性能不能满足他的要求,后来他尝试采用V8引擎,所以选择了C++语言。


Node.js支持的系统包括*nux、Windows,这意味着程序员可以编写系统级或者服务器端的Javascript代码,交给Node.js来解释执行。Node.js的Web开发框架Express,可以帮助程序员快速建立web站点,从2009年诞生至今,Node.js的成长的速度有目共睹,其发展前景获得了技术社区的充分肯定。


Socket.IO

Socket.IO是一个开源的WebSocket库,它通过Node.js实现WebSocket服务端,同时也提供客户端JS库。Socket.IO支持以事件为基础的实时双向通讯,它可以工作在任何平台、浏览器或移动设备。


Socket.IO支持4种协议:WebSocket、htmlfile、xhr-polling、jsonp-polling,它会自动根据浏览器选择适合的通讯方式,从而让开发者可以聚焦到功能的实现而不是平台的兼容性,同时Socket.IO具有不错的稳定性和性能。


编码实现

本文一开始的的插图就是效果演示图:可以点击这里查看在线演示,整个开发过程非常简单,下面简单记录了开发步骤:


安装Node.js

根据自己的操作系统,去Node.js官网下载安装即可。如果成功安装。在命令行输入node -v和npm -v应该能看到相应的版本号。


搭建WebSocket服务端

这个环节我们尽可能的考虑真实生产环境,把WebSocket后端服务搭建成一个线上可以用域名访问的服务,如果你是在本地开发环境,可以换成本地ip地址,或者使用一个虚拟域名指向本地ip。


先进入到你的工作目录,比如 /workspace/wwwroot/plhwin/realtime.plhwin.com,新建一个名为package.json的文件,内容如下:


接下来使用npm命令安装express和socket.io


安装成功后,应该可以看到工作目录下生成了一个名为node_modules的文件夹,里面分别是express和socket.io,接下来可以开始编写服务端的代码了,新建一个文件:index.js


命令行运行node index.js,如果一切顺利,你应该会看到返回的listening on *:3000字样,这说明服务已经成功搭建了。此时浏览器中打开 localhost:3000 应该可以看到正常的欢迎页面。


如果你想要让服务运行在线上服务器,并且可以通过域名访问的话,可以使用Nginx做代理,在nginx.conf中添加如下配置,然后将域名(比如:realtime.plhwin.com)解析到服务器IP即可。


完成以上步骤,realtime.plhwin.com:3000的后端服务就正常搭建了。


服务端代码实现

前面讲到的index.js运行在服务端,之前的代码只是一个简单的WebServer欢迎内容,让我们把WebSocket服务端完整的实现代码加入进去,整个服务端就可以处理客户端的请求了。完整的index.js代码如下:


客户端代码实现

进入客户端工作目录/workspace/wwwroot/plhwin/demo.plhwin.com/chat,新建一个index.html:

上面的html内容本身没有什么好说的,我们主要看看里面的4个文件请求:
1、realtime.plhwin.com:3000
2、style.css
3、json3.min.js
4、client.js


第1个JS是Socket.IO提供的客户端JS文件,在前面安装服务端的步骤中,当npm安装完socket.io并搭建起WebServer后,这个JS文件就可以正常访问了。

第2个style.css文件没什么好说的,就是样式文件而已。

第3个JS只在IE8以下版本的IE浏览器中加载,目的是让这些低版本的IE浏览器也能处理json,这是一个开源的JS,详见:JSON 3

第4个client.js是完整的客户端的业务逻辑实现代码,它的内容如下:


至此所有的编码开发工作全部完成了,在浏览器中打开 demo.plhwin.com/chat/ 就可以看到效果了。

上面所有的客户端和服务端的代码可以从Github上获得,地址:github.com/plhwin/nodej





下载本地后有两个文件夹 client 和 server,client文件夹是客户端源码,可以放在Nginx/Apache的WebServer中,也可以放在Node.js的WebServer中。后面的server文件夹里的代码是websocket服务端代码,放在Node.js环境中,使用npm安装完 express 和 socket.io 后,node index.js 启动后端服务就可以了。


留给我们的思考

1、假设是一个在线客服系统,里面有许多的公司使用你的服务,每个公司自己的用户可以通过一个专属URL地址进入该公司的聊天室,聊天是一对一的,每个公司可以新建多个客服人员,每个客服人员可以同时和客户端的多个用户聊天。


2、又假设是一个在线WebIM系统,实现类似微信,qq的功能,客户端可以看到好友在线状态,在线列表,添加好友,删除好友,新建群组等,消息的发送除了支持基本的文字外,还能支持表情、图片和文件。


有兴趣的同学可以继续深入研究。


--------------------------


上面是我前段时间写的一篇与WebSocket这个主题相关的文档,就直接贴过来了,原文请见:使用Node.js+Socket.IO搭建WebSocket实时应用

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。