websocket 通信协议(已更新到version 13)
2013-08-20 14:11
190 查看
websocket 通信协议(已更新到version 13)
UPDATE:前些天有网友mail和我讨论websocket协议,当时颇忙!更惭愧的是,此篇文章竟已不能使用,原因是当时我写的还是websocket草稿时候的协议!终于,我将websocket 协议更新到了version 13版本 —–2012.5.19
websocket通信协议实现的是基于浏览器的原生socket,在客户端用JS即可轻松完成,前些天都在学习websocket 协议(但实际上websocket 协议甚为简约),并且粗略的思考过websocket的对于下一代web应用会产生怎样的影响,我想最大的巨变应该是就是实时性上吧!另外诸如上传大文件之类的优于http的应用。但问题也随之而来,服务端怎么办?前些天我弄了个websocket 聊天室的demo,现在还得在服务器上专门开个进程来跑呢,也许到时候不再是简单架设个web server就能跑应用的了。也许过不了多久,会出不同的服务端方案吧!先期待一下。websocket的协议是很简单的,这里我把它分成客户端和服务端来讲。在客户端,new WebSocket即可实例化一个新的websocket对象,但其参数略微有一点不一样,参数格式是这样的ws://yourdomain:port/path ,这个从我的聊天室demo里面就可以轻松看出(ws = new
WebSocket( “ws://www.zendstudio.net:9108/chat” ); ),WebSocket对象会自动解析这段字符串,发送到指定服务器端口,首先执行的是双方握手(handshake),客户端发送数据格式类似这样:
GET /chat HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: www.zendstudio.net:9108 Origin: http://www.zendstudio.net Sec-WebSocket-Key: U00QUfV1CRfIIU0NkcUCnA== Sec-WebSocket-Version: 13 Sec-WebSocket-Extensions: x-webkit-deflate-frame |
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 7GGzyIJjf9bX7pej+3tc5Vv87S0= WebSocket-Origin: http://www.zendstudio.net WebSocket-Location: ws://www.zendstudio.net:9108/chat |
(2012.5.19新增内容)这里我们发现,version 13这个版本的websocket协议,与我之前文中叙述之最大不同就是多了一个验证,客户端会发送一个“Sec-WebSocket-Key”的base64编码的密钥,要求服务端必须返回一个“Sec-WebSocket-Accept”,否则客户端会抛出一个“Error during WebSocket handshake: Sec-WebSocket-Accept mismatch”错误之后,关闭连接,当然,这个Sec-WebSocket-Accept的值是计算出来的,胡乱的返回也是要遭到历史唾弃的。Sec-WebSocket-Accept的算法很简单:将客户端提交的Sec-WebSocket-Key+”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″,然后sha1,然后base64_encode,以下列出我用nodejs写的代码片段:
sha1 = crypto.createHash('sha1'); sha1.update(headers["Sec-WebSocket-Key"]+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); ws_accept=sha1.digest('base64'); |
服务端呢?服务端也是非常简单的,但是仍然需要注意的问题是,作为服务器,安全和性能是不可忽略的,除此之外,只管往socket里面写数据就可以了,websocket的通信数据全部是以”\x00″开头以”\xFF”结尾的,无论是服务端发出的数据还是客户端发送的数据都遵从这个格式,唯一不同的是客户端的WebSocket对象能够自动将头尾去除,获得主体数据,这就省却了我们在客户端处理原始数据的必要,真是个体贴周到的对象啊!顺便说一句,WebSocket通信数据的编码总是UTF-8格式的。
服务端相对于草稿版还是改动很大的,从Sec-WebSocket-Extensions部分的声明来看,websocket是会支持压缩的,现在这个version 13版本已经不是当初的utf-8传字符的版本了,而是完全的二进制传输,服务端和客户端的通信经过了mask转换,这样就不太容易看出原文的内容了。这其中的算法颇有些复杂,并非一两句能够说的清楚,这里我写了两个函数来打包和解包数据:
/** * * 打包数据,实际上payload_len == 127时的打包方法是有待商榷的,这里先这样简单实现 * **/ function parse_msg(data){ data = data || null; if( ( data.length <= 0 ) || ( !Buffer.isBuffer(data) ) ){ return null; } var mask_flag = (data[1] & 0x80 == 0x80) ? 1 : 0;//All frames sent from client to server have this bit set to 1. var payload_len = data[1] & 0x7F;//0111 1111 if( payload_len == 126 ){ masks = data.slice(4,8); payload_data = data.slice(8); payload_len = data.readUInt16BE(2); }else if( payload_len == 127 ){ masks = data.slice(10,14); payload_data = data.slice(14); payload_len = data.readUInt32BE(2) * Math.pow(2,32) + data.readUInt32BE(6); }else{ masks = data.slice(2,6); payload_data = data.slice(6); } //console.log(payload_len); //console.log(payload_data.length); for( var i=0;i< payload_len;i++ ){ payload_data[i]= payload_data[i] ^ masks[i%4]; } return payload_data; } /** * 很简陋的实现打包,并且不支持mask,不支持其他命令,不支持拆包、装包、不支持大于16位长度的数据…… **/ function build_msg( str_msg, mask ){ str_msg = str_msg || ""; mask = mask || false; var msg_len = Buffer.byteLength(str_msg,"utf-8"), packed_data; if( msg_len <= 0 ){ return null; } if( msg_len < 126 ){ packed_data = new Buffer(2+msg_len); packed_data[0] = 0x81; packed_data[1] = msg_len; packed_data.write( str_msg, 2 ); }else if( msg_len <= 0xFFFF ){//用16位表示数据长度 packed_data = new Buffer(4 + msg_len); packed_data[0] = 0x81; packed_data[1] = 126; packed_data.writeUInt16BE( msg_len, 2 ); packed_data.write( str_msg, 4 ); }else{//用64位表示数据长度 /*packed_data = new Buffer(10+msg_len); packed_data[0] = 0x81; packed_data[1] = 127; packed_data.writeUInt32BE(msg_len & 0xFFFF0000 >> 32, 2); packed_data.writeUInt32BE(msg_len & 0xFFFF, 6); packed_data.write( str_msg, 10 );*/ } return packed_data; } |
好了,websocket协议就是这么简单。到这里,写一个服务端应该不是什么困难的事情了吧?这仅仅需要一点点socket编程知识,任何语言都可以轻松实现。另外,我想说下源码的事情,有童鞋给我留言希望看看我的服务端源码,我想想还是算了,当我公布的源码徒增自己一堆麻烦,因为一部分人把我当成写应用的了,他们总是会说:“这代码怎么不能用?”,或者说“你能再修改下源代码,以便实现下我们公司当前需要用到的XXX功能吗?”我本为技术交流,之前公布飞信php源代码的时候,就遇到太多这样的情况,我并没有为飞信php建立项目,我不可能花很多时间去跟踪飞信协议变化,不断维护我的代码。同样的,这次的websocket
php服务端源代码我也不打算献丑了,还是不了。非常感谢大家持久以来的支持,希望我们能继续讨论技术本身。
参考文章:http://dev.w3.org/html5/websockets/
http://tools.ietf.org/html/rfc6455
相关文章推荐
- websocket 通信协议(已更新到version 13
- websocket 通信协议(已更新到version 13
- websocket 通信协议
- 【unknown】WebSocket:(基于TCP的)通信协议
- websocket 通信协议
- Socket.IO:支持WebSocket协议、用于实时通信和跨平台的框架
- websocket 通信协议
- android利用websocket协议与服务器通信
- 服务端使用c++实现websocket协议解析及通信
- Websocket——php实战(version 13)
- 13.进程间通信---网络通信(TCP协议和UDP协议的比较)
- Socket.IO:支持WebSocket协议、用于实时通信和跨平台的框架
- WebSocket详解(三):深入WebSocket通信协议细节
- Websocket一个持久化网络通信的协议
- Cocos2d中的网络通信协议(Socket通讯,http协议,WebSocket协议)
- WebSocket 网络通信协议
- 解决HTTP数据不更新问题——no-cache在HTTP通信协议中的应用收藏
- 【物联网智能网关-13】Html5:Canvas+WebSocket实现远程实时通信(上)
- WebSocket通信协议 API简介
- 解决HTTP数据不更新问题——no-cache在HTTP通信协议中的应用