惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Help Net Security
Help Net Security
月光博客
月光博客
N
News and Events Feed by Topic
Cloudbric
Cloudbric
博客园 - 司徒正美
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
The Register - Security
The Register - Security
The Hacker News
The Hacker News
I
InfoQ
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
Kaspersky official blog
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
F
Fortinet All Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
C
Cisco Blogs
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
Latest news
Latest news
PCI Perspectives
PCI Perspectives
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
T
Tor Project blog
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

博客园 - 沧海一声笑

阿里云服务器被挖矿minerd入侵的解决办法 Visor 隐藏应用之一 CSS3 生成器 Visro 应用的前端模板工具介绍 -JsRender 如何在HTML5 Canvas 里面显示 Font Awesome 图标 visor 发布 在一个老外微信PM的眼中,中国移动App UI那些事儿 7个步骤:让JavaScript变得更好 HTML5全局属性和事件 HTML5适合移动应用开发的几大特性 JQuery 应用-JQuery.groupTable.js(二) JQuery 应用-JQuery.groupTable.js - 沧海一声笑 - 博客园 DataGridView控件用法合集 .Net 字符串编码和转换 浅析ASP.NET 3.5与ASP.NET 4.0主要差别 单点登录的实现思路(转) jquery 实现iframe 自适应高度 中国惠普前总裁孙振耀的毕生经验之谈 jquery之旅-jquery的Ajax SQL Server 2008 对 T-SQL 语言的增强
Websocket 协议解析
沧海一声笑 · 2014-12-17 · via 博客园 - 沧海一声笑

WebSocket protocol 是HTML5一种新的协议。它是实现了浏览器与服务器全双工通信(full-duplex)。

       现 很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。

       而最比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求。

       在 WebSocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送,改变了原有的B/S模式。

       在这里是关于Websocket在 php 中的实现,这篇文章里,我主要对websocket 协议进行一个简单的介绍。

Websocket 业务模型

浏览器端的websocket 请求一般是

 // javacsript

  var ws = new WebSocket("ws://127.0.0.1:4000");

  ws.onopen = function(){

    console.log("succeed");

  };

  ws.onerror = function(){

    console.log(“error”);

  };

  ws.onmessage = function(e){

  console.log(e); 

  }

当 new 一个 websocket 对象之后,就会向服务器发送一个 get 请求

       这个请求是对摸个服务器的端口发送的,一般的话,会预先在服务器将一个socket 绑定到一个端口上,客户端和服务器端在这个预定的端口上通信(我这里绑定的就是 4000 端口,默认情况下,websocke 使用 80 端口)。

       然 后,在服务器端的socket监听到这个packet 之后就生成一个新的 socket,将发送过来的数据中的 Sec-WebSocket-Key 解析出来,然后按照把“Sec-WebSocket-Ke”加上一个魔幻字符串“258EAFA5-E914-47DA-95CA- C5AB0DC85B11”。使用SHA-1加密,之后进行BASE-64编码,将结果做为“Sec-WebSocket-Accept”头的值,返回给 客户端。

       客户端收到这个之后,就会将 通信协议 upgrade 到 websocket 协议。

       然后就会在这个持久的通道下进行通信,包括浏览器的询问,服务器的push,双方是在一个全双工的状态下相互通信。 切换后的websocket 协议中的 数据传输帧的格式(此时不再使用html协议) 官方文档给出的说明:

       直接看这个,谁都会有点头大: 我花了一幅图来简单的解释这个 frame 的结构。

各字段的解释:

FIN              1bit 表示信息的最后一帧,flag,也就是标记符

RSV 1-3        1bit each 以后备用的 默认都为 0

Opcode         4bit 帧类型,

Mask              1bit 掩码,是否加密数据,默认必须置为1 

Payload len   7bit 数据的长度,当这个7 bit的数据 == 126 时,后面的2 个字节也是表示数     据长度,当它 == 127 时,后面的 8 个字节表示数据长度Masking-key      1 or 4 bit 掩码Payload data  playload len  bytes 数据

       所以我们这里的代码,通过判断 Playload len的值,来用 substr 截取 Masking-key 和 PlayloadData。

       根据掩码解析数据的方法是:

for( i = 0; i < data.length ; i++){

   orginalData += data[i]  ^  maskingKey[i mod 4]; 

}

       在PHP中,当我们收到数据之后,按照这里的格式截取数据,并将其按照这里的方法解析后就得到了浏览器发送过来的数据。 当我们想把数据发送给浏览器时,也要按照这个格式组装frame。 这里是我的方法:

  function frame($s){

  $a = str_split($s, 125);

  if (count($a) == 1){

  return "\x81" . chr(strlen($a[0])) . $a[0];

  }

  $ns = "";

  foreach ($a as $o){

  $ns .= "\x81" . chr(strlen($o)) . $o;

  }

  return $ns;

 }

       强 行将要发送的数据分割成 125 Byte / frame,这样 playload len 只需要 7 bits。也就是直接将数据的长度的ascall码拼接上去,然后后面跟上要发送的数据。 每一个 frame 前面加的 ‘\x81’ 用二进制就是: 1000 0001 1000 :

1 是 FIN

000 是三个备用的bit

0001 : 指的是 opcode 官方的解释:

       可以设置 opcode的值,来告诉浏览器这个frame的数据属性。