详解websocket协议
⼀、websocket是什么?
websocket 是⼀个基于应⽤层的⽹络协议,建⽴在tcp 协议之上,和 http 协议可以说是兄弟的关系,但是这个兄弟有点依赖 http ,为什么这么说呢?我们都知道 HTTP 实现了三次握⼿来建⽴通信连接,实际上 websocket 的创始⼈很聪明,他不想重复的去造轮⼦,反正我兄弟已经实现了握⼿了,我⼲嘛还要重写⼀套呢?先让它去冲锋陷阵呢,我坐收渔翁之利不是更⾹ 吗,所以⼀般来说,我们会先⽤ HTTP 先进⾏三次握⼿,再向服务器请求升级为websocket 协议,这就好⽐说,嘿兄弟你先去给我排个队占个坑位建个⼩房⼦,到时候我在把这房⼦改造成摩天⼤楼。⽽且⼀般来说 80 和 443 端⼝⼀般 web 服务端都会外放出去,这样可以有效的避免防⽕墙的限制。当然,你创建的websocket 服务端进程的端⼝也需要外放出去。
很多⼈会想问,web开发 使⽤ HTTP 协议不是已经差不多够⽤了吗?为什么还要我再多学⼀种呢?这不是搞事情嘛,仔细想想,⼀门新技术的产⽣必然有原因的,如果没有需求,我们⼲嘛那么蛋疼去写那么多东西,就是因为 HTTP 这个协议有些业务需求⽀持太过于鸡肋了,从 HTTP 0.9 到现在的 HTTP3.0 ,HTTP协议可以说说是在普通的web开发领域已经是⼗分完善且⾼效的了,说这个协议养活了全球半数的公司也不为过吧,像 2.0 服务器推送技术,3.0 采⽤了 UDP ⽽放弃了原来的 TCP ,这些改动都是为了进⼀步提升协议的性能,然⽽⼤家现在还是基本使⽤的 HTTP 1.1 这个最为经典的协议, 也是让开发者挺尴尬的。
绝⼤多数的web开发都是应⽤层开发者,⼤多数都是基于已有的应⽤层去开发应⽤,可以说我们最熟悉、⽇常打交道最多的就是应⽤层协议了,底下 TCP/IP 协议我们基本很少会去处理,当然⼤⼚可能就不⼀样了,⾃⼰弄⼀套协议也是正常的,这⼤概也是程序员和码农的区别吧,搬砖还是创新,差别还是很⼤的。⽹络这种分层协议的好处我在之前的⽂章也说过了,这种隔离性很⽅便就可以让我们基于原来的基础去拓展,具有较好的兼容性。
总的来说,它就是⼀种依赖HTTP协议的,⽀持全双⼯通信的⼀种应⽤层⽹络协议。
⼆、websocket 能解决什么问题?
⼯程师应该是以解决问题为主的,如果不会解决问题,只会伸⼿,必然不会长远,有思考,才会有突破,才能⾼效的处理事情,所以websocket 到底解决了什么问题呢?它存在的价值是什么?
这还是得从HTTP说起,⼤家应该都很熟悉这门协议,我们简单说⼀下它的特点:
三次握⼿、四次挥⼿ 的⽅式建⽴连接和关闭连接
⽀持长连接和短连接两种连接⽅式
有同源策略的限制(端⼝,协议,域名)
前端websocket怎么用
单次 请求-响应 机制,只⽀持单向通信
其中最鸡肋的就是最后⼀个特点,单向通信,什么意思呐?就是说只能由⼀⽅发起请求(客户端),另⼀⽅响应请求(服务端),⽽且每⼀次的请求都是⼀个单独的事件,请求之间还⽆法具有关联性,也就是说我上个请求和下个请求完全是隔离的,⽆法具有连续性。
也许你觉得这样的说法⽐较难懂,我们来举⼀个栗⼦:
每个⼈都打过电话吧,电话打通后可以⼀直聊天是不是觉得很舒服啊,这是⼀种全双⼯的通信⽅式,双⽅都可以主动传递信息。彼此的聊天也具有连续性。我们简单把这种⽅式理解为 websocket 协议⽀持的⽅式。
如果打电话变成了 HTTP 那种⽅式呢? 那就不叫打电话了,⽽是联通爸爸的智能语⾳助⼿了,我们知道客户端和服务端本⾝的⾝份并不是固定的,只要你可以发起通信,就可以充当客户端,能响应请求,就可以当做服务端,但是在HTTP的世界⾥⼀般来说,客户端(⼤多数情况下是浏览器)和服务器⼀般是固定的,我们打电话 去查话费,会询问要⼈⼯服务还是智能助⼿,如果选了助⼿,你只要问她问题,她就会对应的答案来回答你(响应你),⼀般都是简单的业务,你不问她也不会跟你闲聊,主动才有故事啊!
但是实际上有很多的业务是需要双⽅都有主动性的,半双⼯的模式肯定是不够⽤的,例如聊天室,跟机器⼈聊天没意思啊,⼜例如主动推送,我⽆聊的时候⼿都不想点屏幕,你能不能主动⼀点给我推⼀些好玩的信息过来。
只要做过前后端分离的同学应该都被跨域的问题折磨过。浏览器的这种同源策略,会导致 不同端⼝/不同域名/不同协议 的请求会有限制,当然这问题前后端都能处理,然⽽ websocket 就没有这种要求,他⽀持任何域名或者端⼝的访问(协议固定了只能是 ws/wss) ,所以它让⼈⽤的更加舒服
所以,上⾯ HTTP 存在的这些问题,websocket 都能解决
三、websocket 的⼯作原理
主动是 websocket 的⼀⼤特点,像之前如果客户端想知道服务端对某个事件的处理进度,就只能通过轮训( Poll )的⽅式去询问,⼗分的耗费资源,会存在⼗分多的⽆效请求,下⾯我简单说推送技术的三种模型区别:
pull (主动获取) 即客户端主动发起请求,获取消息
poll (周期性主动获取) 即周期性的主动发起请求,获取消息
push (主动推送) 服务端主动推送消息给客户端
pull 和 poll 的唯⼀区别只在于周期性,但是很明显周期性的去询问,对业务来说清晰度很⾼,这也是为什么很多⼩公司都是基于轮训的⽅式去处理业务,因为简单嘛,能⼒不够机器来撑。这也是很多公司都会⾯临的问题,如果业务达到了瓶颈,使劲的堆机器,如果⽤新技术或者更⾼级的作法,开发成本和维护成本也会变⾼,还不如简单⼀点去增加机器配置。
如果两个⼈需要通话,⾸先需要建⽴⼀个连接,⽽且必须是⼀个长链接,⼤家都不希望讲⼏句话就得重新打吧,根据上⾯说
的,websocket 会复⽤之前 HTTP 建⽴好的长链接,然后再进⾏升级,所以他和轮训的区别⼤致如下所⽰
(图⽚来源于⽹上)
图⽚省去了建⽴连接的过程,我们可以发现,基于轮训的⽅式,必须由客户端⼿动去请求,才会有响应,⽽基于 websocket 协议,不再需要你主动约妹⼦了,妹⼦也可以主动去约你,这才是公平的世界。
为了更好的阐述这个连接的原理,可以使⽤swoole ⾃带的 创建websocket 的功能进⾏测试,服务端代码如下,如果连接不上,可以看看是不是检查⼀下端⼝开放情况(iptables/filewall)和⽹络的连通性,代码如下:
<?php
//创建websocket服务器对象,监听0.0.0.0:9501端⼝
$ws=new Swoole\WebSocket\Server("0.0.0.0",9501);
//监听WebSocket连接打开事件
$ws->on('open',function($ws,$request){
var_dump($request->fd,$request->get,$request->server);//request 对象包含请求的相关信息
/
/$ws->push($request->fd, "hello, welcome\n");
});
//监听WebSocket消息事件
$ws->on('message',function($ws,$frame){// frame 是存储信息的变量,也就是传输帧echo"Message: {$frame->data}\n";
$ws->push($frame->fd,"server: {$frame->data}");
});
//监听WebSocket连接关闭事件
$ws->on('close',function($ws,$fd){// fd 是客户端的标志
echo"client-{$fd} is closed\n";
});
$ws->start();// 启动这个进程
通过 php-cli 我们可以启动这个常驻进程。 可以通过 netstat 命令 查看对应端⼝的监听情况
这⾥我就不写客户端了,直接⽤⽹上现成的客户端进⾏测试,我在此实验使⽤的⽹站是这个:
连接成功后我们可以看到两条记录,上⾯是该端⼝的监听情况,代表监听所有IP的9501端⼝信息 下⾯那条是由于我已经⽤客户端创建好的⼀个连接。
我们通过wireshark 可以抓到相关的报⽂ 我们来解释⼀下这个图
⾸先前三个 tcp 连接很明显就是三次握⼿了,然后第⼀个 HTTP 报⽂是请求升级为 websocket 的报⽂,我们可以把对应的应⽤层报⽂弄出来看⼀下
截图的这两个地⽅就是升级的关键了,connection 字段代表这是⼀个升级请求,upgrade 表⽰升级的是 websocket 协议 ,然后服务端⼜回复了⼀个 101 的 HTTP报⽂表⽰正在切换中,如下图所⽰
当连接建⽴完成后,我们为了保持这个连接,服务端会定时发送基于 tcp 的⼼跳包,我们可以通过抓包看到相关的报⽂
如果客户端长时间不响应,说明它挂壁了,那么服务端就会把这个连接进⾏关闭。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。