- 浏览: 215337 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (124)
- 一段耗CPU的随机生成字符串的代码,why? (1)
- 生活如何才能不匆忙? (1)
- Null Object设计模式 (1)
- 珍爱生命,远离java (1)
- Oracle强杀进程,解决表锁死等问题 (1)
- java发送消息到RTX提醒 (1)
- 以HTTP形式获取图片流并写入另一个图片 (1)
- struts2获取Session和request方法 (1)
- 洛克菲勒.第一封:起点不决定终点 (1)
- tomcat的OutOfMemoryError解决方法 (1)
- REST和SOAP:谁更好,或者都好? (1)
- 35款免费的Javascript、Flash Web图表组件 (1)
- 盘点:三十五个非主流开源数据库 (1)
- Lucene并发连接实现 - ConcurrentLuceneConnection (1)
- 能大大提升工作效率和时间效率的9个重要习惯 (1)
- 读周鸿祎的《乔布斯的拿来主义》后感 (1)
- 表变量与临时表的优缺点 (1)
- Visual C++线程同步技术剖析 (转载) (1)
- 海量数据处理专题1——Bloom Filter (1)
- 海量数据处理专题2——Hash (1)
- 海量数据处理专题3——Bit-map (1)
- 海量数据处理专题4——堆 (1)
- 海量数据处理专题5——双层桶划分 (1)
- 海量数据处理专题6——数据库索引及优化 (1)
- 海量数据处理专题7——倒排索引(搜索引擎之基石) (1)
- 如何让优化你在搜索引擎上的形象 (1)
- 20个专业的SEO网站分析工具 (1)
- 杯具了,武汉开出国内首张个人网店税单:征税430余万 (1)
- java关键字的实现原理 (1)
- 关于Class类的成员函数与Java反射机制,坦言Synchronize的本质 (1)
- iBATIS的一对多关联查询 (1)
- 详解spring 依赖注入的作用 (1)
- 为什么要用JSP做显示而不用servlet? (1)
- 解决:java webservice调用net 参数返回NULL (1)
- Lucene搜索 关键字高亮 (1)
- Java常用类 Object类简单用法和深入 (1)
- 我在上海奋斗五年 从月薪3500到700万 (1)
- 每个Java初学者都应该搞懂的六个问题 (1)
- 强 奸数据库就这八步! (0)
- 数据库就这八步! (1)
- 什么才是最好处理中文方法 (1)
- JS实现简单的ajax访问Struts2的action类 (1)
- 跨域终极解决办法 (1)
- 由Map的复制问题引发对深复制和浅复制的思考 (1)
- Object类型转换为String类型的两种方式 (1)
- 写Java程序的三十个基本规则 (1)
- java计算时间差及某个时间段数据 (1)
- 推荐10个Java开源CMS系统 (1)
- 折半插入排序java实现 (1)
- 什么是程序员的优秀品质? (1)
- JDK Proxy AOP实现 (1)
- Java的最优化内存管理 (1)
- 100个Java经典例子 (1)
- java多态反射机制例子 (1)
- hashCode与equals的区别与联系 (1)
- 软件公司如何才能留住员工 (1)
- Java模拟操作系统进程调度算法—先来先服务、短作业优先、高响比优先 (1)
- 抛砖引玉 教你如何成为一名Java初级程序员 (1)
- 是什么成就了一名“高级”程序员? (1)
- 10分钟教会你Apache Shiro (1)
- Lucene排序 Payload的应用 (1)
- Lucene3.0之结果排序 (1)
- synchronized和java.util.concurrent.locks.Lock的异同 (1)
- 如何把Object对象转换为XML (1)
- 大流量网站的底层系统架构 (1)
- 程序员应该知道的100个vim命令 (1)
- 小编辑 Java 6 JVM参数选项大全(中文版) (1)
- 使用 Java Native Interface 的最佳实践 (1)
- 您适合从事Web前端开发行业吗? (1)
- 一个当了爹的程序员的自白 (1)
- Hibernate中设置MySQL的中文编码 (1)
- 雅虎声明称董事会运转良好 杨致远无需辞职 (1)
- IBM开源Java语言变种NetRexx (1)
- Tomcat VS Jetty (1)
- 正版office 2007 简体中文专业版(附正版序列号)高速下载正版office 2007 简体中文专业版 (1)
- java程序员应该知道的两种引用 (1)
- 基于Oracle 分布式数据库的查询优化 (1)
- JAVA设计模式 (1)
- java高并发-静态页面生成方案(1) (1)
- 程序员和编码员之间的区别 (1)
- 看看美国是如何解决开发人员的缺陷的 (1)
- ClassNotFoundException: org.springframework.web.util.IntrospectorCleanupListener (1)
- 开发模式 (0)
最新评论
-
泛黄秋颜:
大神你好,我最近在做云显示,奈何就是不会,能不能麻烦您发我一份 ...
Java实现标签云 -
Zhang_amao:
我的QQ邮箱1101232017@qq.com
Java实现标签云 -
Zhang_amao:
您好, 我现在也在研究这一领域,特别需要java版本来生成中文 ...
Java实现标签云 -
moon198654:
Technoboy 写道引用
总结
本文介绍了目前 Java ...
Tomcat VS Jetty -
mengxiangzhou:
dfvdf
Java模拟操作系统进程调度算法—先来先服务、短作业优先、高响比优先
webSocket 服务器端的简单实现
webSocket 服务器端的简单实现
上周研究了一下HTML5.
发现很多令人激动的功能。
路漫漫其修远兮,吾将上下而求索!
1. 内置数据库
2. 支持WebSocket
3. 支持多线程
4. 支持本地存储
但是,仍然处于草案中的 WebSocket 竟然找不到合适的服务器,刚好工作比较闲,用来三天时间自己写了一个。
功能有点简单!设计上也有很大缺陷。只能简单的发送信息,和推送信息。
而且现在的协议还不成熟,不久就有一个版本出现!昨天看到才是V16,今天出V17了。
简
单介绍一下 WebSocket 它是实现了浏览器与服务器的全双工信息传输。Websocket协议基于Http 的 Upgrade
头和101的响应进行协议切换。经过简单的握手协议,建立一个长连接,按照协议的规则进行数据的传输。具体介绍可以参考google.
1.握手协议
版本0--3中:
握手通过请求头Sec-WebSocket-Key1 和 Sec-WebSocket-Key2 的值和 8 字节的请求实体,进行MD5加密,将加密结果,构造出一个16字节作为请求实体的内容返回。如下实例:
------------------请求--------------------------------------------
- GET /demo HTTP/1.1
- Host: example.com
- Connection: Upgrade
- Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
- Sec-WebSocket-Protocol: sample
- Upgrade: WebSocket
- Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
- Origin: http://example.com
- (\r\n)
- ^n:ds[4U
------------------响应--------------------------------------------
- HTTP/1.1 101 WebSocket Protocol Handshake
- Upgrade: WebSocket
- Connection: Upgrade
- Sec-WebSocket-Origin: http://example.com
- Sec-WebSocket-Location: ws://example.com/demo
- Sec-WebSocket-Protocol: sample
- (\r\n)
- 8jKS'y:G*Co,Wxa-
------------------------------------------------------------------
把
第一个Key中的数字除以第一个Key的空白字符的数量,而第二个Key也是如此,这样得到两个整数,把每个整数写的四个字节里去,串为8个字
节,然后和请求实体里面的8个字节串为16字节,将这16个字节进行MD5加密(如实例中的结果:8jKS'y:G*Co,Wxa-),得到一个16字节
的数据作为响应实体的内容,返回给客户端,这样握手成功。
代码实现:
- int len = 8; // in.available();
- byte[] key3 = new byte[len];
- if (in.read(key3) != len)
- throw new RuntimeException();
- log.debug(HelpUtil.formatBytes(key3));
- String key1 = requestHeaders.get("Sec-WebSocket-Key1");
- String key2 = requestHeaders.get("Sec-WebSocket-Key2");
- int k1 = HelpUtil.parseWebsokcetKey(key1);
- int k2 = HelpUtil.parseWebsokcetKey(key2);
- byte[] sixteenByte = new byte[16];
- System.arraycopy(HelpUtil.intTo4Byte(k1), 0, sixteenByte, 0, 4);
- System.arraycopy(HelpUtil.intTo4Byte(k2), 0, sixteenByte, 4, 4);
- System.arraycopy(key3, 0, sixteenByte, 8, 8);
- byte[] md5 = MessageDigest.getInstance("MD5").digest(sixteenByte);
在版本4之后,握手协议修改了:
------------------请求--------------------------------------------
- GET /chat HTTP/1.1
- Host: server.example.com
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
- Sec-WebSocket-Origin: http://example.com
- Sec-WebSocket-Protocol: chat, superchat
- (\r\n)
------------------响应--------------------------------------------
- HTTP/1.1 101 Switching Protocols
- Upgrade: websocket
- Connection: Upgrade
- Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
- Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
- Sec-WebSocket-Protocol: chat
使
用请求头的值
Sec-WebSocket-Key,该值是BASE-64编码(base64-encoded)的,我们不需要转码,加上一个魔幻字符串:
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",(结果:
[dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11])使用 SHA-1
加密,之后进行 BASE-64编码,将结果做为 Sec-WebSocket-Accept 头的值,返回给客户端。
如果服务器端有
Sec-WebSocket-Nonce 头,表示要在Sec-WebSocket-Key 的值,和魔幻字符串之间加入该
Sec-WebSocket-Nonce
头的值,即“dGhlIHNhbXBsZSBub25jZQ==AQIDBAUGBwgJCgsMDQ4PEC==258EAFA5-
E914-47DA-95CA-C5AB0DC85B11”,进行 SHA-1 加密,之后和前面的相同。完成握手协议。
- public static final String GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- public static final String HEADER_CODE = "iso-8859-1";
- String code = requestHeaders.get("Sec-WebSocket-Key") + GUID;
- byte[] bts = MessageDigest.getInstance("SHA1").digest(code.getBytes(HEADER_CODE));
- code = HelpUtil.getBASE64(bts);
- resMap.put("Sec-WebSocket-Accept", code);
握手完成就是数据帧的传输了。
在版本 0 中, 数据帧比较的简单。数据帧以 0x00 开头,以0xFF结尾,中间的数据以utf-8编码的字符就可以了。当然这个简单的格式只能用来传输字符串。无法传输字节流。所以 版本 1 就做了修改了,后面的版本绝大部分是兼容的。
后面的这个帧结构就有点复杂了,如下所示(一行是4个字节,32 bit):
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-------+-+-------------+-------------------------------+
- |M|R|R|R| opcode|R| Payload len | Extended payload length |
- |O|S|S|S| (4) |S| (7) | (16/63) |
- |R|V|V|V| |V| | (if payload len==126/127) |
- |E|1|2|3| |4| | |
- +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
- | Extended payload length continued, if payload len == 127 |
- + - - - - - - - - - - - - - - - +-------------------------------+
- | | Extension data |
- +-------------------------------+ - - - - - - - - - - - - - - - +
- : :
- +---------------------------------------------------------------+
- : Application data :
- +---------------------------------------------------------------+
(后续的版本略有修改)
获取数据长度
- int dataLen = bt & PAYLOADLEN;
- if (dataLen == HAS_EXTEND_DATA) {// read next 16 bit
- bt = in.read();
- b2 = in.read();
- fram.setDateLength(HelpUtil.toShort((byte) bt, (byte) b2));
- } else if (dataLen == HAS_EXTEND_DATA_CONTINUE) {// read next 32 bit
- byte[] bts = new byte[8];
- if (in.read(bts) != 8){
- //fram.setOpcode
- throw new RuntimeException(
- "reader Payload-Len-Extended-Continued data length < 64 bit");
- }
- fram.setDateLength(HelpUtil.toLong(bts));
- } else {
- fram.setDateLength(dataLen);
- }
[MORE] 表示一个数据通过多个帧进行传输, 如果是 0 表示后面还有数据帧,如果是 1 则表示是最后一个帧。
[RSV1][RSV2][RSV3][RSV4] 未做定义暂时全为零。
[opcode] 标识数据的格式,以及帧的控制,如:08标识数据内容是 文本,01标识:要求远端去关闭当前连接。
[Payload len] 如果小于126 表示后面的数据长度是 [Payload len] 的值。(最大125byte)
等于 126 表示之后的16 bit位的数据值标识数据的长度。(最大65535byte)
等于 127 表示之后的64 bit位的数据值标识数据的长度。(一个有符号长整型的最大值)
[Extension data]没有提及怎么使用。
[Application data] 为应用提供的数据。
版本7之后,添加了 MASK 的概念。相当于对数据加密。而且要求客户端必须是MASK的。
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-------+-+-------------+-------------------------------+
- |F|R|R|R| opcode|M| Payload len | Extended payload length |
- |I|S|S|S| (4) |A| (7) | (16/63) |
- |N|V|V|V| |S| | (if payload len==126/127) |
- | |1|2|3| |K| | |
- +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
- | Extended payload length continued, if payload len == 127 |
- + - - - - - - - - - - - - - - - +-------------------------------+
- | |Masking-key, if MASK set to 1 |
- +-------------------------------+-------------------------------+
- | Masking-key (continued) | Payload Data |
- +-------------------------------- - - - - - - - - - - - - - - - +
- : Payload Data continued ... :
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
- | Payload Data continued ... |
- +---------------------------------------------------------------+
[opcode] 01标识数据内容是 文本,08标识 : 要求远端去关闭当前连接。
[MASK](即原先的RSV4)如果是 1 则数据是被 MASK 的。
[Masking-key]
如果MASK为 1 则有4字节的 Masking-key,用于与传输的数据 [Payload Data]
进行异或运算,4byte(32bit)进行一次运算,不足四位从前往后对应,如只有三位,则只与[Masking-key]的前三位进行运算。
解码 MASK 数据,使用了一个过滤流
- @Override
- public int read() throws IOException {
- if (readLength >= length)
- return -1;
- int b = 0;
- synchronized (lock) {
- if (readLength >= length)
- return -1;
- b = super.read();
- if (isMask) {
- b ^= maskKey[(int) (readLength % 4)];
- }
- readLength++;
- }
- return b;
- }
关于流的关闭:一般情况我们可以直接 使用socket.close() 进行关闭,客户端JS状态会显示 webSocket.readyState 的值为 2 (正在关闭的状态)。需要我们通过握手去要求远端关闭流。
有三个版本:
在版本 0 时:传两个字节 (0xff,0x00);
在版本 1--6 时:传三个字节 (0x80,0x01,0x00);
在版本 7--以上 时:传两个字节 (0x88,0x00);
经测试 只有 在版本 7--以上 时:传两个字节 (0x88,0x00); 这时可以实现 webSocket.readyState 的值为 3。
估计是我的代码有问题。如有发现请告知,谢谢!
websocket 协议: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10 (其他版本查看相关链接)
源码SVN地址:http://lineblog.googlecode.com/svn/trunk/ 下面的目录
httpAnalysis/src/com/googlecode/lineblog/websocket/
相关推荐
内容概要:本文详细介绍了基于MATLAB GUI界面和卷积神经网络(CNN)的模糊车牌识别系统。该系统旨在解决现实中车牌因模糊不清导致识别困难的问题。文中阐述了整个流程的关键步骤,包括图像的模糊还原、灰度化、阈值化、边缘检测、孔洞填充、形态学操作、滤波操作、车牌定位、字符分割以及最终的字符识别。通过使用维纳滤波或最小二乘法约束滤波进行模糊还原,再利用CNN的强大特征提取能力完成字符分类。此外,还特别强调了MATLAB GUI界面的设计,使得用户能直观便捷地操作整个系统。 适合人群:对图像处理和深度学习感兴趣的科研人员、高校学生及从事相关领域的工程师。 使用场景及目标:适用于交通管理、智能停车场等领域,用于提升车牌识别的准确性和效率,特别是在面对模糊车牌时的表现。 其他说明:文中提供了部分关键代码片段作为参考,并对实验结果进行了详细的分析,展示了系统在不同环境下的表现情况及其潜在的应用前景。
嵌入式八股文面试题库资料知识宝典-计算机专业试题.zip
嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_3.zip
内容概要:本文深入探讨了一款额定功率为4kW的开关磁阻电机,详细介绍了其性能参数如额定功率、转速、效率、输出转矩和脉动率等。同时,文章还展示了利用RMxprt、Maxwell 2D和3D模型对该电机进行仿真的方法和技术,通过外电路分析进一步研究其电气性能和动态响应特性。最后,文章提供了基于RMxprt模型的MATLAB仿真代码示例,帮助读者理解电机的工作原理及其性能特点。 适合人群:从事电机设计、工业自动化领域的工程师和技术人员,尤其是对开关磁阻电机感兴趣的科研工作者。 使用场景及目标:适用于希望深入了解开关磁阻电机特性和建模技术的研究人员,在新产品开发或现有产品改进时作为参考资料。 其他说明:文中提供的代码示例仅用于演示目的,实际操作时需根据所用软件的具体情况进行适当修改。
少儿编程scratch项目源代码文件案例素材-剑客冲刺.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 转瞬即逝.zip
内容概要:本文详细介绍了基于PID控制器的四象限直流电机速度驱动控制系统仿真模型及其永磁直流电机(PMDC)转速控制模型。首先阐述了PID控制器的工作原理,即通过对系统误差的比例、积分和微分运算来调整电机的驱动信号,从而实现转速的精确控制。接着讨论了如何利用PID控制器使有刷PMDC电机在四个象限中精确跟踪参考速度,并展示了仿真模型在应对快速负载扰动时的有效性和稳定性。最后,提供了Simulink仿真模型和详细的Word模型说明文档,帮助读者理解和调整PID控制器参数,以达到最佳控制效果。 适合人群:从事电力电子与电机控制领域的研究人员和技术人员,尤其是对四象限直流电机速度驱动控制系统感兴趣的读者。 使用场景及目标:适用于需要深入了解和掌握四象限直流电机速度驱动控制系统设计与实现的研究人员和技术人员。目标是在实际项目中能够运用PID控制器实现电机转速的精确控制,并提高系统的稳定性和抗干扰能力。 其他说明:文中引用了多篇相关领域的权威文献,确保了理论依据的可靠性和实用性。此外,提供的Simulink模型和Word文档有助于读者更好地理解和实践所介绍的内容。
嵌入式八股文面试题库资料知识宝典-2013年海康威视校园招聘嵌入式开发笔试题.zip
少儿编程scratch项目源代码文件案例素材-驾驶通关.zip
小区开放对周边道路通行能力影响的研究.pdf
内容概要:本文探讨了冷链物流车辆路径优化问题,特别是如何通过NSGA-2遗传算法和软硬时间窗策略来实现高效、环保和高客户满意度的路径规划。文中介绍了冷链物流的特点及其重要性,提出了软时间窗概念,允许一定的配送时间弹性,同时考虑碳排放成本,以达到绿色物流的目的。此外,还讨论了如何将客户满意度作为路径优化的重要评价标准之一。最后,通过一段简化的Python代码展示了遗传算法的应用。 适合人群:从事物流管理、冷链物流运营的专业人士,以及对遗传算法和路径优化感兴趣的科研人员和技术开发者。 使用场景及目标:适用于冷链物流企业,旨在优化配送路线,降低运营成本,减少碳排放,提升客户满意度。目标是帮助企业实现绿色、高效的物流配送系统。 其他说明:文中提供的代码仅为示意,实际应用需根据具体情况调整参数设置和模型构建。
少儿编程scratch项目源代码文件案例素材-恐怖矿井.zip
内容概要:本文详细介绍了基于STM32F030的无刷电机控制方案,重点在于高压FOC(磁场定向控制)技术和滑膜无感FOC的应用。该方案实现了过载、过欠压、堵转等多种保护机制,并提供了完整的源码、原理图和PCB设计。文中展示了关键代码片段,如滑膜观测器和电流环处理,以及保护机制的具体实现方法。此外,还提到了方案的移植要点和实际测试效果,确保系统的稳定性和高效性。 适合人群:嵌入式系统开发者、电机控制系统工程师、硬件工程师。 使用场景及目标:适用于需要高性能无刷电机控制的应用场景,如工业自动化设备、无人机、电动工具等。目标是提供一种成熟的、经过验证的无刷电机控制方案,帮助开发者快速实现并优化电机控制性能。 其他说明:提供的资料包括详细的原理图、PCB设计文件、源码及测试视频,方便开发者进行学习和应用。
基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf
嵌入式八股文面试题库资料知识宝典-CC++笔试题-深圳有为(2019.2.28)1.zip
少儿编程scratch项目源代码文件案例素材-几何冲刺 V1.5.zip
Android系统开发_Linux内核配置_USB-HID设备模拟_通过root权限将Android设备转换为全功能USB键盘的项目实现_该项目需要内核支持configFS文件系统
C# WPF - LiveCharts Project
少儿编程scratch项目源代码文件案例素材-恐怖叉子 动画.zip
嵌入式八股文面试题库资料知识宝典-嵌⼊式⼯程师⾯试⾼频问题.zip