您的位置:首页 > 其它

websocekt原理及实现过程

2017-03-27 19:29 411 查看

1.websocket协议:

可以将 WebSocket看成是一种类似TCP/IP的socket技术;此socket在Web应用中实现,并获得了和TCP/IP通信一样灵活方便的全双向通信功能。

WebSocket协议由RFC 6455定义。协议分为两个部分: 握手阶段和数据通信阶段。

WebSocket为应用层协议,其定义在TCP/IP协议栈之上。

WebSocket连接服务器的URI以”ws”或者”wss”开头。ws开头的默认TCP端口为80,wss开头的默认端口为443。

Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。

2.websocket的优点:

1)通过第一次HTTP Request建立了连接之后,后续的数据交换都不用再重新发送HTTP Request,节因此它省了带宽资源;

2) WebSocket的连接是双向通信的连接,在同一个TCP连接上,既可以发送,也可以接收;

3)具有多路复用的功能(multiplexing),也就是说几个不同的URI可以复用同一个WebSocket连接。

3.websocket的作用:

在说明白websocket的作用之前,还是先弄清楚轮询以及long poll的好,如此才能更好的对比出websocket的作用以及他的好处。

a.轮询:

轮询呢,顾名思义就是每隔几一段时间去做一件事情,这里就是每隔一定的时间,客户端就向web服务器发一次请求,请求当前的新数据。

轮询却是是一个合理的方案,但是有时候他的效率就不是很高,因为轮询就意为这要向服务器发起请求,要不断的建立新的连接,而这样做只是为了知道是否有新的数据,试想一下如果有成千上万的用户都这样轮询,时间一长服务器受得了吗?

是不是不太理解?O=O,,,,,没关系,简单的说,,,,

比如:你喜欢某个蛋糕店,于是在那里办了个会员卡,想着只要蛋糕出新你就去买,,于是就出现如下对话(前提,这个老板有健忘症,放下你的会员卡就忘记你是谁了):

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:没有。

,,,,,过了一天,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:没有,没有。

,,,,,又过了一天,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:没有。

,,,,,又过了一天,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:你咋这么烦,没有没有没有。

,,,,,又过了一天,你还是厚着脸皮去了,,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:给给给,拿走,烦死人

,,,,,于是你开开心心的走了,可是吃完后你又去了,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:没!有!

,,,,,过了一天,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?

老板(Response)检查了会员卡:没有。

,,,,,,于是你陷入了无限询问有没有新蛋糕中,,,,,,,

这就是轮询,,,想想,要是有很多个你这样的人,,那老板过几天是不是得进精神病院啊,,,,,^_^!

咱们来看看图:



b.long poll:

long poll 其实原理跟 轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消息才返回,返回完之后,客户端再次建立连接,周而复始。

场景再现:

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?没有的话就算了,等有了给我打电话叫我罢。

老板(Response)检查了会员卡,记下你的电话,默默地不回话。

,,,,,于是你就一直等着,过了好几天,你的电话才响,,,,,,

老板(Response):给,给你新蛋糕。

,,,,,你很开心的取回蛋糕,很快吃完了,于是你又去了蛋糕店,,,,,

你(Request)将会员卡递给老板:老板,有没有出新蛋糕啊?没有的话就算了,等有了给我打电话叫我罢。

老板(Response)检查了会员卡,记下你的电话,默默地不回话。

,,,,,于是你就一直等着,过了好几天,你的电话才响,,,,,,

老板(Response):给,给你新蛋糕。

如此,你又陷入了无限的询问与等待中,,,,

这就是long poll 即为长轮询,O(*)O|||

看图看图:



c.websocket:

终于到主角了,,

通过上面两个对话,我们可以看出,这两种方式都不是最好的,需要很多资源,也浪费了很多的带宽。

况且HTTP还是一个状态协议。

通俗的说就是,服务器因为每天要接待太多客户了,是个健忘鬼,你一离开,他就把你的东西全忘光了,把你的东西全丢掉了。你第二次还得再告诉服务器一遍。

所以在这种情况下出现了,Websocket出现了。他解决了HTTP的这几个难题。

首先,被动性,当服务器完成协议升级后(HTTP->Websocket),服务端就可以主动推送信息给客户端啦。所以情景可以做如下修改:

你(Request):老板,我们用websocket联系罢,需要的服务:chat,Websocket协议版本:17(HTTP Request)

老板(Response)检查了会员卡:嗯,已升级为最新版。

你(Request):那,老板要是出了新蛋糕,记得告诉我哦。

老板(Response):好的,有的话就告诉你。

。。。。。于是你就回家敲代码去了。。。。。。

老板(Response):今天出了草莓蛋糕,你快来,,,

。。。。。你欢欢喜喜的取回蛋糕,继续敲代码。。。。。

老板(Response):今天有巧克力蛋糕哦

。。。。。你欢欢喜喜的取回蛋糕,继续敲代码。。。。。

老板(Response):………….

老板(Response):………….

就变成了这样,只需要经过一次HTTP请求,就可以做到源源不断的信息传送了。(在程序设计中,这种设计叫做回调,即:你有信息了再来通知我,而不是我傻乎乎的每次跑来问你 )

客户端和服务器建立TCP连接之后,客户端发送握手请求,随后服务器发送握手响应即完成握手阶段,看图看图:



来来来,,对话看完了,咱们来总结一下:

这样的协议解决了上面同步有延迟,而且还非常消耗资源的这种情况。那么为什么他会解决服务器上消耗资源的问题呢?

其实我们所用的程序是要经过两层代理的,即HTTP协议在Nginx等服务器的解析下,然后再传送给相应的Handler(PHP等)来处理。简单地说,我们有一个非常快速的 接线员(Nginx) ,他负责把问题转交给相应的 客服(Handler) 。

本身接线员基本上速度是足够的,但是每次都卡在客服(Handler)了,老有客服处理速度太慢。,导致客服不够。

Websocket就解决了这样一个难题,建立后,可以直接跟接线员建立持久连接,有信息的时候客服想办法通知接线员,然后接线员在统一转交给客户。

这样就可以解决客服处理速度过慢的问题了。

同时,在传统的方式上,要不断的建立,关闭HTTP协议,由于HTTP是非状态性的,每次都要重新传输 identity info (鉴别信息),来告诉服务端你是谁。

虽然接线员很快速,但是每次都要听这么一堆,效率也会有所下降的,同时还得不断把这些信息转交给客服,不但浪费客服的处理时间,而且还会在网路传输中消耗过多的流量/时间。

但是Websocket只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,也就避免了HTTP的非状态性,服务端会一直知道你的信息,直到你关闭请求,这样就解决了接线员要反复解析HTTP协议,还要查看identity info的信息。

同时由客户主动询问,转换为服务器(推送)有信息的时候就发送(当然客户端还是等主动发送信息过来的。。),没有信息的时候就交给接线员(Nginx),不需要占用本身速度就慢的客服(Handler)了。

4.websocket示例(客户端使用js):

var websocket = new WebSocket("ws://www.host.com/path");
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) }; }
function onMessage(evt) { alert( evt.data); }
function onError(evt) { alert( evt.data); }
websocket.send("client to server");


a.创建一个WebSocket对象,传入一个URL值,以ws://或者wss://开头,原理和http://和https://相同。

b.使用WebSocket的四个事件:

onopen :会在建立连接后触发

onerror:会在出现问题时触发

onmessage:会在页面接受到消息时触发

onclose:会在连接关闭时触发

c.发送消息:在连接成功后,需要向服务器发送一条消息,发送消息要使用WebSocket对象的send()方法,改方法接受纯文本内容作为参数。

d.服务器在收到消息后就开始处理消息,此时触发onmessage事件

e.在网页认为有必要断开通信时,便调用close()方法

如:socket.close();

注意:一旦关闭socket,便不能再通信了,除非你再次建立websocket对象,再次重复以上的步骤。

5.关闭连接:

任何一端发送关闭帧给对方,即可关闭连接。关闭连接时通常都带有关闭连接的状态码(status code)。常见状态码的含义如下:

1000 连接正常关闭

1001 端点离线,例如服务器down,或者浏览器已经离开此页面

1002 端点因为协议错误而中断连接

1003 端点因为受到不能接受的数据类型而中断连接

1004 目前保留其用法,会在将来给出定义

1005 保留, 用于提示应用未收到连接关闭的状态码

1006 端点异常关闭

1007 端点收到的数据帧类型不一致而导致连接关闭

1008 数据违例而关闭连接

1009 收到的消息数据太大而关闭连接

1010 客户端因为服务器未协商扩展而关闭

1011 服务器因为遭遇异常而关闭连接

1015 TLS握手失败关闭连接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  websocket web通信