//WEBSOKET java SERVICE

http://my.oschina.net/u/590484/blog/71797

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的头信息,同样每行都是以”\r\n”结尾的,上面这段格式无需我们去构造,WebSocket对象会自动发送,对客户端这是透明的。此时服务端应该返回的信息是:

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

从这里我们太容易看出来,websocket协议的握手部分根本就是个类http的协议,所不同的是http每次都会有这样子的头信息交互,这在某些时候不得不显得很糟糕。而websocket只会执行一次这个过程,之后的传输信息就变得异常简洁了。

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');

客户端在握手成功后,会触发WebSocket对象的onopen事件,告诉客户端连接已经成功建立了。客户端的WebSocket对象一共绑定了四个事件:1、onopen:连接建立时触发;2、onmessage:收到服务端消息时触发;3、onerror:连接出错时触发;4、onclose:连接关闭时触发;有了这4个事件,我们就可以很容易很轻松的驾驭websocket,并且需要说明的是websocket支持二进制数据的传输,因此,它远不止聊天室应用这么简单。

服务端呢?服务端也是非常简单的,但是仍然需要注意的问题是,作为服务器,安全和性能是不可忽略的,除此之外,只管往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;
}

这两个都是没有完整实现的方法,要完美实现,得需要根据rfc6455来做了。(另外我同时把demo给更新了,欢迎围观

好了,websocket协议就是这么简单。到这里,写一个服务端应该不是什么困难的事情了吧?这仅仅需要一点点socket编程知识,任何语言都可以轻松实现。另外,我想说下源码的事情,有童鞋给我留言希望看看我的服务端源码,我想想还是算了,当我公布的源码徒增自己一堆麻烦,因为一部分人把我当成写应用的了,他们总是会说:“这代码怎么不能用?”,或者说“你能再修改下源代码,以便实现下我们公司当前需要用到的XXX功能吗?”我本为技术交流,之前公布飞信php源代码的时候,就遇到太多这样的情况,我并没有为飞信php建立项目,我不可能花很多时间去跟踪飞信协议变化,不断维护我的代码。同样的,这次的websocket php服务端源代码我也不打算献丑了,还是不了。非常感谢大家持久以来的支持,希望我们能继续讨论技术本身。

websocket 通信协议的更多相关文章

  1. WebSocket通信协议 API简介

    WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如 Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从ch ...

  2. WebSocket通信协议

    var ws = new WebSocket("ws://echo.websocket.org"); ws.onopen = function(){ws.send("Te ...

  3. Web通信协议:OSI、TCP、UDP、Socket、HTTP、HTTPS、TLS、SSL、WebSocket、Stomp

    1      各层的位置 1.1      OSI七层模型全景图 OSI是Open System Interconnect的缩写,意为开放式系统互联. 1.2      五层网络协议 在七层的基础上, ...

  4. WebSocket介绍和一个简单的聊天室

    WebSocket是什么呢? WebSocket一种在单个 TCP 连接上进行全双工通讯的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范, ...

  5. 网页实时聊天之PHP实现websocket

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  6. Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

    1. 前言 Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Serve ...

  7. WebSocket协议开发

    一直以来,网络在很大程度上都是围绕着HTTP的请求/响应模式而构建的.客户端加载一个网页,然后直到用户点击下一页之前,什么都不会发生.在2005年左右,Ajax开始让网络变得更加动态了.但所有的HTT ...

  8. 使用线程池模拟处理耗时任务,通过websocket提高用户体验

    前言 在文章开始之前,询问一下大家平时工作中后端处理批量任务(耗时任务)的时候,前端是如何告知用户任务的执行情况的? 楼主对这个问题想了下,决定使用websokect将这一过程展现给用户. 于是就有了 ...

  9. WebSocket 浅析

    版权声明:本文由史燕飞原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/241 来源:腾云阁 https://www.qclo ...

随机推荐

  1. lightoj 1038 Race to 1 Again

    题意:给一个数,用这个数的因数除以这个数,直到为1时,求除的次数的期望. 设一个数的约数有M个,E[n] = (E[a[1]]+1)/M+(E[a[2]]+1)/M+...+(E[a[M]]+1)/M ...

  2. boost signal2 trackable

    挺简单的一个类,只是维护了一个成员 shared_ptr<detail::trackable_pointee> _tracked_ptr; 这样看来的话,所谓的track还是基于智能指针, ...

  3. 监控mysql执行的sql语句

    linux平台 监控mysql执行的sql语句   为了做好配合开发做性能和功能测试,方便监控正在执行的sql语句, 可以在/etc/mysqld中添加如下:  log =/usr/local/mys ...

  4. Android viewpager 嵌套 viewpager滑动 点击事件冲突解决方案

    为了解决这个问题.可以自定义viewpager,然后在里面监听首饰,自定义点击事件 package com.hpuvoice.view; import android.content.Context; ...

  5. 从零开始PHP学习 - 第一天

    写这个系列文章主要是为了督促自己  每天定时 定量消化一些知识! 同时也为了让需要的人 学到点啥~! 本人技术实在不高!本文中可能会有错误!希望大家发现后能提醒一下我和大家! 偷偷说下 本教程最后的目 ...

  6. Entity Framework 数据部分更新之Attach &&Detach

    我们经常会遇到这样的问题:Update一个entity的部分数据时,通常需要new一个新的对象,然后事这新的对象Attach到Context中,代码如下所示: /// <summary> ...

  7. JS知识点摘记(一)

    JavaScript:基于对象和事件的脚本语言 特点: 安全性:不允许直接访问本地硬盘,可做的就是信息的动态交互 跨平台性:只要可以解析JS的浏览器就可执行,与平台无关 JavaScript与Java ...

  8. 对Msn协议的一点点研究

    这个也是好奇msn的协议还是2011年的时候写的, 就在网上找啊找啊, 可惜要不是不能用就是C++代码还有就是不完整, 到最后我也没弄成功,只到了下面这步就挂掉了...... 登录成功<=SBS ...

  9. Get Intellisense for .axml files in Visual Studio

    原文Get Intellisense for .axml files in Visual Studio So in order to get some intellisense support for ...

  10. git创建标签

    创建标签 在Git中打标签非常简单,首先,切换到需要打标签的分支上: $ git branch * dev master $ git checkout master Switched to branc ...