注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小葫芦君(汉斯的博客)

博客迁移到新博客:https://blog.ssxingshou.com

 
 
 

日志

 
 
关于我

小小葫芦商城,为您提供高品质的商品,一流的产品,一流的包装服务,一流的物流服务,放心购买

网易考拉推荐

基于netty的websocket开发小结  

2014-04-13 12:08:41|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
WebSocket是html5规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用WebSocket技术,后台可以随时向前端推送消息,以保证前后台状态统一,在传统的无状态HTTP协议中,这是“无法做到”的。 

WebSocket提出之前,为了解决后台推送消息到前台的需求,提出了一些解决方案,这些方案使用已有的技术(如ajax,iframe,flashplayer,java applet ...),通过一些变通的处理来实现。 

webSocket是html5新引入的技术,允许后台随时向前端发送文本或者二进制消息,WebSocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法: 
ws://127.0.0.1:8080/websocket。ws不是http,所以传统的web服务器不一定支持,需要服务器与浏览器同时支持, WebSocket才能正常运行,目前的支持还不普遍,需要特别的web服务器和现代的浏览器。 

浏览器对WebSocket的支持 
Google Chrome浏览器最先支持WebSocket,随后是Safari,Firefox,此外最新版本的Opera和IE(Opera11,IE10)也支持WebSocket。 

客户端WebSocket的主要方法 

1 构造函数 
Java代码  收藏代码
  1. var websocket = new WebSocket("ws://127.0.0.1:8080/websocket");  

2 事件open/message/close/error 
WebSocket#onopen, onmessage, onclose, onerror 
连接打开时,回调onopen方法,接收到后台消息时会触发到onmessage事件,后台关闭时调用onclose,出现连接异常时可在onerror中捕获 
发送消息 - WebSocket#send(data) 
关闭连接 - WebSocket#close(optional code, optional reason) 

下面是一个简单的html5连接websocket服务器测试页 
Html代码  收藏代码
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4.   
  5. <script type="text/javascript" charset="utf-8" >  
  6.   windowwindow.WebSocket = window.WebSocket || window.MozWebSocket;  
  7.     
  8.  if (!window.WebSocket){  
  9.      alert("WebSocket not supported by this browser");  
  10.      return;  
  11.  };  
  12.     
  13. var websocket = new WebSocket("ws://127.0.0.1:8080/websocket");  
  14.  websocket.onmessage = function(evt){  
  15.      var data = evt.data;  
  16.       alert("received message: " + data);  
  17.  }  
  18.   
  19.  function send() {  
  20.  var name = document.querySelector("input[namename=name]").value;  
  21.     alert("websocket send message:"+name);  
  22.     websocket.send(name);  
  23.  }  
  24. </script>  
  25. </head>  
  26. <body>  
  27. <label for="name">What’s your name:</label>  
  28. <input type="text" id="name" name="name" />  
  29. <button onclick="send()">Send</button>  
  30. <div id="message" style="color:red"></div>  
  31. </body>  
  32. </html>  


服务器对WebSocket的支持 
    WebSocket不同于http协议,传统的web服务器通常不支持WebSocket.而websocket服务器端的开发大概有借助Socket.IO开发、NodeJS和Socket.IO联合开发以及借助netty框架开发等等。这里只对netty框架下的websocket开发进行一个简单的说明! 

    websocket的协议比较简单, 客户端和普通的浏览器一样通过80或者443端口和服务器进行请求握手,服务器根据http header识别是否一个websocket请求,如果是,则将请求升级为一个websocket连接,握手成功后就进入双向长连接的数据传输阶段. websocket的数据传输是基于帧的方式: 0x00 表示数据开始, 0xff表示数据结束,数据以utf-8编码. 

    简单的说,第一次请求客户端发送的是http请求,请求头中包含websocket相关的信息,服务器端对请求进行验证: 

Java代码  收藏代码
  1. private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {  
  2.      // Allow only GET methods.  
  3.      if (req.getMethod() != GET) {  
  4.          sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));  
  5.          return;  
  6.      }  
  7.   
  8.      // Send the demo page and favicon.ico  
  9.      if (req.getUri().equals("/")) {  
  10.          HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);  
  11.   
  12.          ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));  
  13.   
  14.          res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");  
  15.          setContentLength(res, content.readableBytes());  
  16.   
  17.          res.setContent(content);  
  18.          sendHttpResponse(ctx, req, res);  
  19.          return;  
  20.      } else if (req.getUri().equals("/favicon.ico")) {  
  21.          HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);  
  22.          sendHttpResponse(ctx, req, res);  
  23.          return;  
  24.      }  
  25.   
  26.      // Handshake  
  27.      WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(  
  28.              this.getWebSocketLocation(req), nullfalse);  
  29.      this.handshaker = wsFactory.newHandshaker(req);  
  30.      if (this.handshaker == null) {  
  31.          wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());  
  32.      } else {  
  33.          this.handshaker.handshake(ctx.getChannel(), req);  
  34.          System.out.println(WebSocketServer.recipients.size());  
  35.          WebSocketServer.recipients.add(ctx.getChannel());  
  36.          System.out.println(WebSocketServer.recipients.size());  
  37.          System.out.println(ctx.getChannel().getId());  
  38.      }  
  39.  }  


验证成功后,将请求升级为一个websocket连接,之后的通信就进入双向长连接的数据传输阶段。 

Java代码  收藏代码
  1. private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {  
  2.   
  3.     // Check for closing frame  
  4.     if (frame instanceof CloseWebSocketFrame) {  
  5.         this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);  
  6.         return;  
  7.     } else if (frame instanceof PingWebSocketFrame) {  
  8.         ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));  
  9.         return;  
  10.     } else if (!(frame instanceof TextWebSocketFrame)) {  
  11.         throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()  
  12.                 .getName()));  
  13.     }  
  14.   
  15.     // Send the uppercase string back.  
  16.     String request = ((TextWebSocketFrame) frame).getText();  
  17.     logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));  
  18.   
  19.       WebSocketServer.recipients.write(new TextWebSocketFrame(request.toUpperCase()));  
  20.     ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));  
  21. }  


一定要注意在messageReceived中要对HttpRequest和WebSocketFrame分别进行处理。 
Java代码  收藏代码
  1. public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {  
  2.     Object msg = e.getMessage();  
  3.     if (msg instanceof HttpRequest) {  
  4.         handleHttpRequest(ctx, (HttpRequest) msg);  
  5.     } else if (msg instanceof WebSocketFrame) {  
  6.         handleWebSocketFrame(ctx, (WebSocketFrame) msg);  
  7.     }  
  8. }  


服务入口 
Java代码  收藏代码
  1. package com.etao.mobile.websocket;  
  2.   
  3. import java.net.InetSocketAddress;  
  4. import java.util.concurrent.Executors;  
  5.   
  6. import org.jboss.netty.bootstrap.ServerBootstrap;  
  7. import org.jboss.netty.channel.group.ChannelGroup;  
  8. import org.jboss.netty.channel.group.DefaultChannelGroup;  
  9. import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;  
  10.   
  11. /** 
  12.  * A HTTP server which serves Web Socket requests at: 
  13.  *  
  14.  * http://localhost:8080/websocket 
  15.  *  
  16.  * Open your browser at http://localhost:8080/, then the demo page will be 
  17.  * loaded and a Web Socket connection will be made automatically. 
  18.  *  
  19.  * This server illustrates support for the different web socket specification 
  20.  * versions and will work with: 
  21.  *  
  22.  * <ul> 
  23.  * <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00) 
  24.  * <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00) 
  25.  * <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10) 
  26.  * <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17) 
  27.  * <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10) 
  28.  * </ul> 
  29.  */  
  30. public class WebSocketServer {  
  31.   
  32.     private final int port;  
  33.   
  34.     public static ChannelGroup recipients = new DefaultChannelGroup();  
  35.   
  36.     public WebSocketServer(int port) {  
  37.         this.port = port;  
  38.     }  
  39.   
  40.     public void run() {  
  41.         // Configure the server.  
  42.         ServerBootstrap bootstrap = new ServerBootstrap(  
  43.                 new NioServerSocketChannelFactory(Executors  
  44.                         .newCachedThreadPool(), Executors.newCachedThreadPool()));  
  45.   
  46.         // Set up the event pipeline factory.  
  47.         bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());  
  48.   
  49.         // Bind and start to accept incoming connections.  
  50.         bootstrap.bind(new InetSocketAddress(port));  
  51.   
  52.         System.out.println("Web socket server started at port " + port + '.');  
  53.         System.out  
  54.                 .println("Open your browser and navigate to http://localhost:"  
  55.                         + port + '/');  
  56.     }  
  57.   
  58.     public static void main(String[] args) {  
  59.         int port;  
  60.         if (args.length > 0) {  
  61.             port = Integer.parseInt(args[0]);  
  62.         } else {  
  63.             port = 8080;  
  64.         }  
  65.         new WebSocketServer(port).run();  
  66.     }  
  67. }  


一定要注意的是netty3.0一下的版本是不支持websocket的!我这里用的是3.3.0.Final版本。 

可能存在的隐患:不同草案的websocket 握手标准有所不同,因此netty在这方面的检测是否可以满足要求? 
  评论这张
 
阅读(817)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017