竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


107月/170

WebSocket全双工通信入门教程

发布在 邵珠庆

 1. 什么是WebSocket
           WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。
                1. 传统的web通信方式
                        1. 工作模式:客户端请求-服务端响应
                        2. 适用场景:信息变化不是特别频繁的场合,如网页刷新
                        3. 不适用场景:在线游戏,实时监控
                        4. 问题
                          占用网络传输带宽:每次请求和应答都带有完整的Http头,这就增加了每次传输的数据量。
                          实时性差:在全双工通信时常采用轮询进行。

                2. 改进版web通信方式
                        1. 轮询
                          
                                1. 基于polling(轮询)技术:以频繁请求方式来保持客户端和服务端的同步
                                2. 问题:客户端的频繁的请求,服务端的数据无变化,造成通信低效
                        2. 长轮询
                          
                                1. 当服务端没有数据更新的时候,连接会保持一段时间周期直到数据或者状态改变或者过期,以此减少无效的客户端和服务端的交互
                                2. 当服务端数据变更频繁的话,这种机制和定时轮询毫无区别
                        3. 流技术
                          
                                1. 在客户端页面通过一个隐藏的窗口向服务端发出一个长连接请求。服务端接到这个请求后作出回应并不断更新链接状态以保证客户端和服务端的连接不过期。
                                2. 浏览器设计兼容和并发处理问题。
                        4. websocket
                                1. 概念:是html5开始提供的一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。
                                2. 原理和TCP一样,只需做一个握手动作,就可以形成一条快速通道。
                                           
                                        1. 客户端发起http请求,附加头信息为:“Upgrade Websocket”
                                            
                                            
                                        2. 服务端解析,并返回握手信息,从而建立连接
                                            
                                        3. 传输数据(双向)
                                           
                                        4. 断开连接
                                3. 数据传输过程
                                        1. 以帧形式进行传输
                                                1. 大数据分片
                                                2. 支持边生成数据,把你传递消息
                                        2. 说明
                                                1. 客户端到服务端的数据帧必须进行掩码处理,服务端拖接收到未经掩码处理的数据帧,须主动关闭连接
                                                2. 服务端到客户端的数据一定不能加掩码,客户端接收到经过掩码的实际帧,须主动关闭连接
                                                3. 发现错误的一方可以发送close帧,关闭连接。
                                4. 优势
                                        1. 数据传输量大
                                        2. 稳定性高
                                5. 支持浏览器
                                        1. Firefox 4、Chrome 4、Opera 10.70以及Safari 5等浏览器的支持

       2. websocket案例说明
                1. 客户端
                        1. 创建Websocket实例
                          ws = new WebSocket("ws://127.0.0.1:10000/Server_Test.php");
1. 服务器IP:ws://127.0.0.1
2. 服务器端口:10000
3. 服务程序:Server_Test.php
2. 建立连接后回调函数
ws.onopen = function(event){}
3. 收到服务端消息后回调函数
ws.onmessage = function(event){}
4. 关闭连接后回调函数
ws.onclose = function(event){}
5. 连接错误后回调函数
                          ws.onerror = function(event)
6. 发送数据
                          ws.send('服务器,您好');
7. 查看当前连接状态
                          alert(ws.readyState)

    2. 服务端
1. 创建服务端WebSocket对象,等待客户端接入
                          $master  = WebSocket("localhost",10000);

                          首先创建Websocket,然后服务端监听相应端口,等待客户端接入
                          function WebSocket($address,$port){
                            $master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)     or die("socket_create() failed");
                          socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1)  or die("socket_option() failed");
                           socket_bind($master, $address, $port)                    or die("socket_bind() failed");
                           socket_listen($master,20)                                or die("socket_listen() failed");
                          echo "Server Started : ".date('Y-m-d H:i:s')."\n";
                             echo "Master socket  : ".$master."\n";
                           echo "Listening on   : ".$address." port ".$port."\n\n";
                            return $master;
                           }
2. 从WebSocket中读取数据
                          $buffer = socket_read($socket,2048);
3. 当收到客户端首次连接请求后,生成握手信息并回复
                          $return_str = dohandshake($buffer);
                          socket_write($socket,$return_str,strlen($return_str));
4. 连接后,即可接收并解析出客户端的数据
                          $buffer = socket_read($socket,2048);
                          $data_str = decode($buffer);
5. 接收到用户数据后,直接回复客户端
                          socket_write($socket,$return_str,strlen($return_str));
6. 断开连接
                          socket_close($socket);
                        7. 以上6步完成全双工通信
                3. 本案例说明

                        1. 目前只可传文本,byte传输还需进一步研究

        3. 案例运行流程
            首先需要安装PHP study,然后将服务端代码放到PHP study可执行目录下,最后使用浏览器打开客户端代码去访问服务器即可进行通信。

                1. 安装PHP study,然后将PHP文件放到 D:\phpStudy\WWW 
                    
                2. 设置PHP study端口:
                    
                3. 在客户端程序中通过url去访问服务器:
                    

        4. 调试说明

                1. 客户端代码
                        1. html代码使用Hbuilder编辑完成
                        2. 打印信息使用
                          console.log("已经与服务器建立了连接rn当前连接状态:" + this.readyState);
3. 打印信息可以实时输出到控制台
2. 服务端代码
1. 服务端代码编辑同样在Hbuilder中完成
2. 服务端代码调试工具推荐使用Xdebug,我们目前使用的是打印错误日志方式进行调试
                          error_log("客户端发送数据:  $data_str \r\n", 3, "D:/phpStudy/WWW/error.log");
                        3. 注意,D:/phpStudy/WWW/error.log为日志输出路径

        5. 参考资料

                1. 认识Websocket:http://www.itpub.net/thread-1373652-1-1.html###
                2. 认识Websocket (较全面):https://my.oschina.net/u/1266171/blog/357488
                3. websocket讲解:http://wenku.baidu.com/link?url=q-RIde8I-ScuPv6wO1APa8lfX47B-6meTdm7LTNyCcSsSxOqnqzt7WtKEXzwl6YpAVG5KzMcAMRTusknr_6T9w5RC7qbZGa0elRy6b4sTZi
                4. Websocket在线测试工具:http://www.blue-zero.com/WebSocket/
                5. 客户端很简单,关键是服务端代码:http://www.yxsss.com/sg.php?fp=0&tag=websocket
                6. 使用php创建WebSocket服务:http://www.oschina.net/code/snippet_1029305_22256
                7. PHP服务器:http://www.oschina.net/code/snippet_230665_21329
                8. 在线聊天室程序:http://www.yxsss.com/ui/sk.html
                9. 在线聊天室程序详解:http://www.bitscn.com/pdb/php/201609/732585.html
                                                     http://www.111cn.net/phper/php-cy/120076.htm
10. 服务端代码详解:http://zhidao.baidu.com/link?url=cbPCqd2rdNUMqHNKhQKEqF2j5carf01upT6PHGpFFPVLZv7ef5q5avksGyNd5P06nvIltLgHCPN68YZ6Emp2ytT4NVyi1-7CUkghun4zT1i
11. java实现Websocket:http://blog.csdn.net/u011677147/article/details/47038259

107月/170

Web领域的实时推送技术

发布在 邵珠庆

作者:潘良虎
链接:https://www.zhihu.com/question/20215561/answer/26419995
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Web领域的实时推送技术,也被称作Realtime技术。这种技术要达到的目的是让用户不需要刷新浏览器就可以获得实时更新。它有着广泛的应用场景,比如在线聊天室、在线客服系统、评论系统、WebIM等。

WebSocket简介

谈到Web实时推送,就不得不说WebSocket。在WebSocket出现之前,很多网站为了实现实时推送技术,通常采用的方案是轮询(Polling)和Comet技术,Comet又可细分为两种实现方式,一种是长轮询机制,一种称为流技术,这两种方式实际上是对轮询技术的改进,这些方案带来很明显的缺点,需要由浏览器对服务器发出HTTP request,大量消耗服务器带宽和资源。面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并实现真正意义上的实时推送。
WebSocket协议本质上是一个基于TCP的协议,它由通信协议和编程API组成,WebSocket能够在浏览器和服务器之间建立双向连接,以基于事件的方式,赋予浏览器实时通信能力。既然是双向通信,就意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP的请求和响应。
为了建立一个WebSocket连接,客户端浏览器首先要向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的HTTP请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的WebSocket连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
一个典型WebSocket客户端请求头:


前面讲到WebSocket是HTML5中新增的一种通信协议,这意味着一部分老版本浏览器(主要是IE10以下版本)并不具备这个功能, 通过百度统计的公开数据显示,IE8目前仍以33%的市场份额占据榜首,好在chrome浏览器市场份额逐年上升,现在以超过26%的市场份额位居第二,同时微软前不久宣布停止对IE6的技术支持并提示用户更新到新版本浏览器,这个曾经让无数前端工程师为之头疼的浏览器有望退出历史舞台,再加上几乎所有的智能手机浏览器都支持HTML5,所以使得WebSocket的实战意义大增,但是无论如何,我们实际的项目中,仍然要考虑低版本浏览器的兼容方案:在支持WebSocket的浏览器中采用新技术,而在不支持WebSocket的浏览器里启用Comet来接收发送消息。
WebSocket实战本文将以多人在线聊天应用作为实例场景,我们先来确定这个聊天应用的基本需求。
需求分析1、兼容不支持WebSocket的低版本浏览器。
2、允许客户端有相同的用户名。
3、进入聊天室后可以看到当前在线的用户和在线人数。
4、用户上线或退出,所有在线的客户端应该实时更新。
5、用户发送消息,所有客户端实时收取。

在实际的开发过程中,为了使用WebSocket接口构建Web应用,我们首先需要构建一个实现了 WebSocket规范的服务端,服务端的实现不受平台和开发语言的限制,只需要遵从WebSocket规范即可,目前已经出现了一些比较成熟的WebSocket服务端实现,比如本文使用的Node.js+Socket.IO。为什么选用这个方案呢?先来简单介绍下他们两。
Node.jsNode.js采用C++语言编写而成,它不是Javascript应用,而是一个Javascript的运行环境,据Node.js创始人Ryan Dahl回忆,他最初希望采用Ruby来写Node.js,但是后来发现Ruby虚拟机的性能不能满足他的要求,后来他尝试采用V8引擎,所以选择了C++语言。
Node.js支持的系统包括*nux、Windows,这意味着程序员可以编写系统级或者服务器端的Javascript代码,交给Node.js来解释执行。Node.js的Web开发框架Express,可以帮助程序员快速建立web站点,从2009年诞生至今,Node.js的成长的速度有目共睹,其发展前景获得了技术社区的充分肯定。
Socket.IOSocket.IO是一个开源的WebSocket库,它通过Node.js实现WebSocket服务端,同时也提供客户端JS库。Socket.IO支持以事件为基础的实时双向通讯,它可以工作在任何平台、浏览器或移动设备。
Socket.IO支持4种协议:WebSocket、htmlfile、xhr-polling、jsonp-polling,它会自动根据浏览器选择适合的通讯方式,从而让开发者可以聚焦到功能的实现而不是平台的兼容性,同时Socket.IO具有不错的稳定性和性能。
编码实现

本文一开始的的插图就是效果演示图:可以点击这里查看在线演示,整个开发过程非常简单,下面简单记录了开发步骤:
安装Node.js根据自己的操作系统,去Node.js官网下载安装即可。如果成功安装。在命令行输入node -v和npm -v应该能看到相应的版本号。


搭建WebSocket服务端

这个环节我们尽可能的考虑真实生产环境,把WebSocket后端服务搭建成一个线上可以用域名访问的服务,如果你是在本地开发环境,可以换成本地ip地址,或者使用一个虚拟域名指向本地ip。
先进入到你的工作目录,比如 /workspace/wwwroot/plhwin/realtime.plhwin.com,新建一个名为package.json的文件,内容如下:


接下来使用npm命令安装express和socket.io


安装成功后,应该可以看到工作目录下生成了一个名为node_modules的文件夹,里面分别是express和socket.io,接下来可以开始编写服务端的代码了,新建一个文件:index.js


命令行运行node index.js,如果一切顺利,你应该会看到返回的listening on *:3000字样,这说明服务已经成功搭建了。此时浏览器中打开 localhost:3000 应该可以看到正常的欢迎页面。
如果你想要让服务运行在线上服务器,并且可以通过域名访问的话,可以使用Nginx做代理,在nginx.conf中添加如下配置,然后将域名(比如:realtime.plhwin.com)解析到服务器IP即可。


完成以上步骤,realtime.plhwin.com:3000的后端服务就正常搭建了。


服务端代码实现前面讲到的index.js运行在服务端,之前的代码只是一个简单的WebServer欢迎内容,让我们把WebSocket服务端完整的实现代码加入进去,整个服务端就可以处理客户端的请求了。完整的index.js代码如下:


客户端代码实现进入客户端工作目录/workspace/wwwroot/plhwin/demo.plhwin.com/chat,新建一个index.html:

上面的html内容本身没有什么好说的,我们主要看看里面的4个文件请求:
1、realtime.plhwin.com:3000
2、style.css
3、json3.min.js
4、client.js
第1个JS是Socket.IO提供的客户端JS文件,在前面安装服务端的步骤中,当npm安装完socket.io并搭建起WebServer后,这个JS文件就可以正常访问了。

第2个style.css文件没什么好说的,就是样式文件而已。

第3个JS只在IE8以下版本的IE浏览器中加载,目的是让这些低版本的IE浏览器也能处理json,这是一个开源的JS,详见:JSON 3

第4个client.js是完整的客户端的业务逻辑实现代码,它的内容如下:


至此所有的编码开发工作全部完成了,在浏览器中打开 demo.plhwin.com/chat/ 就可以看到效果了。

上面所有的客户端和服务端的代码可以从Github上获得,地址:github.com/plhwin/nodej

下载本地后有两个文件夹 client 和 server,client文件夹是客户端源码,可以放在Nginx/Apache的WebServer中,也可以放在Node.js的WebServer中。后面的server文件夹里的代码是websocket服务端代码,放在Node.js环境中,使用npm安装完 express 和 socket.io 后,node index.js 启动后端服务就可以了。
留给我们的思考

1、假设是一个在线客服系统,里面有许多的公司使用你的服务,每个公司自己的用户可以通过一个专属URL地址进入该公司的聊天室,聊天是一对一的,每个公司可以新建多个客服人员,每个客服人员可以同时和客户端的多个用户聊天。
2、又假设是一个在线WebIM系统,实现类似微信,qq的功能,客户端可以看到好友在线状态,在线列表,添加好友,删除好友,新建群组等,消息的发送除了支持基本的文字外,还能支持表情、图片和文件。
有兴趣的同学可以继续深入研究。
--------------------------
上面是我前段时间写的一篇与WebSocket这个主题相关的文档,就直接贴过来了,原文请见:使用Node.js+Socket.IO搭建WebSocket实时应用