Netty之——基于Netty5.0高级案例NettyWebsocket

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/55026558

一、前言介绍

    本案例主要介绍如何使用Netty开发websocket。

二、环境需求

    1、jdk1.7

    2、Eclipse

    3、Netty5.0

    4、支持websocket的浏览器[火狐]

三、工程截图


四、代码部分

1、服务端
Global.java

[java]  view plain  copy
  1. package com.itstack.netty.common;  
  2. import io.netty.channel.group.ChannelGroup;  
  3. import io.netty.channel.group.DefaultChannelGroup;  
  4. import io.netty.util.concurrent.GlobalEventExecutor;  
  5. public class Global {  
  6.     public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);  
  7.       
  8. }   
ChildChannelHandler.java
[java]  view plain  copy
  1. package com.itstack.netty.websocket;  
  2. import io.netty.channel.ChannelInitializer;  
  3. import io.netty.channel.socket.SocketChannel;  
  4. import io.netty.handler.codec.http.HttpObjectAggregator;  
  5. import io.netty.handler.codec.http.HttpServerCodec;  
  6. import io.netty.handler.stream.ChunkedWriteHandler;  
  7. public class ChildChannelHandler extends ChannelInitializer<SocketChannel>{  
  8.     @Override  
  9.     protected void initChannel(SocketChannel e) throws Exception {  
  10.           
  11.         e.pipeline().addLast("http-codec",new HttpServerCodec());  
  12.         e.pipeline().addLast("aggregator",new HttpObjectAggregator(65536));  
  13.         e.pipeline().addLast("http-chunked",new ChunkedWriteHandler());  
  14.         e.pipeline().addLast("handler",new MyWebSocketServerHandler());  
  15.     }  
  16. }   
MyWebSocketServerHandler.java
[java]  view plain  copy
  1. package com.itstack.netty.websocket;  
  2. import java.util.Date;  
  3. import java.util.logging.Level;  
  4. import java.util.logging.Logger;  
  5. import com.itstack.netty.common.Global;  
  6. import io.netty.buffer.ByteBuf;  
  7. import io.netty.buffer.Unpooled;  
  8. import io.netty.channel.ChannelFuture;  
  9. import io.netty.channel.ChannelFutureListener;  
  10. import io.netty.channel.ChannelHandlerContext;  
  11. import io.netty.channel.SimpleChannelInboundHandler;  
  12. import io.netty.handler.codec.http.DefaultFullHttpRequest;  
  13. import io.netty.handler.codec.http.DefaultFullHttpResponse;  
  14. import io.netty.handler.codec.http.FullHttpRequest;  
  15. import io.netty.handler.codec.http.HttpResponseStatus;  
  16. import io.netty.handler.codec.http.HttpVersion;  
  17. import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;  
  18. import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;  
  19. import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;  
  20. import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;  
  21. import io.netty.handler.codec.http.websocketx.WebSocketFrame;  
  22. import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;  
  23. import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;  
  24. import io.netty.util.CharsetUtil;  
  25. public class MyWebSocketServerHandler extends  
  26.         SimpleChannelInboundHandler<Object> {  
  27.     private static final Logger logger = Logger  
  28.             .getLogger(WebSocketServerHandshaker.class.getName());  
  29.     private WebSocketServerHandshaker handshaker;  
  30.     @Override  
  31.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  32.         // 添加  
  33.         Global.group.add(ctx.channel());  
  34.         System.out.println("客户端与服务端连接开启");  
  35.     }  
  36.     @Override  
  37.     public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
  38.         // 移除  
  39.         Global.group.remove(ctx.channel());  
  40.         System.out.println("客户端与服务端连接关闭");  
  41.     }  
  42.     @Override  
  43.     protected void messageReceived(ChannelHandlerContext ctx, Object msg)  
  44.             throws Exception {  
  45.         if (msg instanceof FullHttpRequest) {  
  46.             handleHttpRequest(ctx, ((FullHttpRequest) msg));  
  47.         } else if (msg instanceof WebSocketFrame) {  
  48.             handlerWebSocketFrame(ctx, (WebSocketFrame) msg);  
  49.         }  
  50.     }  
  51.     @Override  
  52.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
  53.         ctx.flush();  
  54.     }  
  55.     private void handlerWebSocketFrame(ChannelHandlerContext ctx,  
  56.             WebSocketFrame frame) {  
  57.         // 判断是否关闭链路的指令  
  58.         if (frame instanceof CloseWebSocketFrame) {  
  59.             handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame  
  60.                     .retain());  
  61.         }  
  62.         // 判断是否ping消息  
  63.         if (frame instanceof PingWebSocketFrame) {  
  64.             ctx.channel().write(  
  65.                     new PongWebSocketFrame(frame.content().retain()));  
  66.             return;  
  67.         }  
  68.         // 本例程仅支持文本消息,不支持二进制消息  
  69.         if (!(frame instanceof TextWebSocketFrame)) {  
  70.             System.out.println("本例程仅支持文本消息,不支持二进制消息");  
  71.             throw new UnsupportedOperationException(String.format(  
  72.                     "%s frame types not supported", frame.getClass().getName()));  
  73.         }  
  74.         // 返回应答消息  
  75.         String request = ((TextWebSocketFrame) frame).text();  
  76.         System.out.println("服务端收到:" + request);  
  77.         if (logger.isLoggable(Level.FINE)) {  
  78.             logger  
  79.                     .fine(String.format("%s received %s", ctx.channel(),  
  80.                             request));  
  81.         }  
  82.         TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString()  
  83.                 + ctx.channel().id() + ":" + request);  
  84.         // 群发  
  85.         Global.group.writeAndFlush(tws);  
  86.         // 返回【谁发的发给谁】  
  87.         // ctx.channel().writeAndFlush(tws);  
  88.     }  
  89.     private void handleHttpRequest(ChannelHandlerContext ctx,  
  90.             FullHttpRequest req) {  
  91.         if (!req.getDecoderResult().isSuccess()  
  92.                 || (!"websocket".equals(req.headers().get("Upgrade")))) {  
  93.             sendHttpResponse(ctx, req, new DefaultFullHttpResponse(  
  94.                     HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));  
  95.             return;  
  96.         }  
  97.         WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(  
  98.                 "ws://localhost:7397/websocket"nullfalse);  
  99.         handshaker = wsFactory.newHandshaker(req);  
  100.         if (handshaker == null) {  
  101.             WebSocketServerHandshakerFactory  
  102.                     .sendUnsupportedWebSocketVersionResponse(ctx.channel());  
  103.         } else {  
  104.             handshaker.handshake(ctx.channel(), req);  
  105.         }  
  106.     }  
  107.     private static void sendHttpResponse(ChannelHandlerContext ctx,  
  108.             FullHttpRequest req, DefaultFullHttpResponse res) {  
  109.         // 返回应答给客户端  
  110.         if (res.getStatus().code() != 200) {  
  111.             ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),  
  112.                     CharsetUtil.UTF_8);  
  113.             res.content().writeBytes(buf);  
  114.             buf.release();  
  115.         }  
  116.         // 如果是非Keep-Alive,关闭连接  
  117.         ChannelFuture f = ctx.channel().writeAndFlush(res);  
  118.         if (!isKeepAlive(req) || res.getStatus().code() != 200) {  
  119.             f.addListener(ChannelFutureListener.CLOSE);  
  120.         }  
  121.     }  
  122.     private static boolean isKeepAlive(FullHttpRequest req) {  
  123.         return false;  
  124.     }  
  125.     @Override  
  126.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  
  127.             throws Exception {  
  128.         cause.printStackTrace();  
  129.         ctx.close();  
  130.     }  
  131. }   
NettyServer.java
[java]  view plain  copy
  1. package com.itstack.netty.websocket;  
  2. import io.netty.bootstrap.ServerBootstrap;  
  3. import io.netty.channel.Channel;  
  4. import io.netty.channel.ChannelOption;  
  5. import io.netty.channel.EventLoopGroup;  
  6. import io.netty.channel.nio.NioEventLoopGroup;  
  7. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  8. public class NettyServer {  
  9.     public static void main(String[] args) {  
  10.           
  11.         new NettyServer().run();  
  12.     }  
  13.       
  14.     public void run(){  
  15.           
  16.         EventLoopGroup bossGroup = new NioEventLoopGroup();  
  17.         EventLoopGroup workGroup = new NioEventLoopGroup();  
  18.           
  19.         try {  
  20.               
  21.             ServerBootstrap b = new ServerBootstrap();  
  22.             b.group(bossGroup, workGroup);  
  23.             b.channel(NioServerSocketChannel.class);  
  24.             b.childHandler(new ChildChannelHandler());  
  25.               
  26.             System.out.println("服务端开启等待客户端连接 ... ...");  
  27.               
  28.             Channel ch = b.bind(7397).sync().channel();  
  29.               
  30.             ch.closeFuture().sync();  
  31.               
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }finally{  
  35.             bossGroup.shutdownGracefully();  
  36.             workGroup.shutdownGracefully();  
  37.         }  
  38.           
  39.     }  
  40.       
  41. }   
2、客户端
[html]  view plain  copy
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5. <title>无标题文档</title>  
  6. </head>  
  7.   </head>  
  8.   <script type="text/javascript">  
  9.   var socket;  
  10.   
  11.   if(!window.WebSocket){  
  12.    
  13.       window.WebSocket = window.MozWebSocket;  
  14.   }  
  15.    
  16.   if(window.WebSocket){  
  17.       socket = new WebSocket("ws://localhost:7397/websocket");  
  18.         
  19.       socket.onmessage = function(event){  
  20.    
  21.             var ta = document.getElementById('responseText');  
  22.             ta.value += event.data+"\r\n";  
  23.       };  
  24.    
  25.       socket.onopen = function(event){  
  26.    
  27.             var ta = document.getElementById('responseText');  
  28.             ta.value = "打开WebSoket 服务正常,浏览器支持WebSoket!"+"\r\n";  
  29.               
  30.       };  
  31.    
  32.       socket.onclose = function(event){  
  33.    
  34.             var ta = document.getElementById('responseText');  
  35.             ta.value = "";  
  36.             ta.value = "WebSocket 关闭"+"\r\n";  
  37.       };  
  38.   }else{  
  39.         alert("您的浏览器不支持WebSocket协议!");  
  40.   }  
  41.    
  42.   function send(message){  
  43.     if(!window.WebSocket){return;}  
  44.     if(socket.readyState == WebSocket.OPEN){  
  45.         socket.send(message);  
  46.     }else{  
  47.         alert("WebSocket 连接没有建立成功!");  
  48.     }  
  49.       
  50.   }  
  51.         
  52.   </script>  
  53.   <body>  
  54.     <form onSubmit="return false;">  
  55.         <input type = "text" name="message" value="Netty The Sinper"/>  
  56.         <br/><br/>  
  57.         <input type="button" value="发送 WebSocket 请求消息" onClick="send(this.form.message.value)"/>  
  58.         <hr color="blue"/>  
  59.         <h3>服务端返回的应答消息</h3>  
  60.         <textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>  
  61.     </form>  
  62.   </body>  
  63. </html>  

五、测试运行

1、启动NettyServer

2、启动支持websocket的浏览器,打开index.html【开启2个以上】

3、服务端输出结果:

服务端开启等待客户端连接 ... ...
客户端与服务端连接开启
客户端与服务端连接开启
客户端与服务端连接关闭
客户端与服务端连接开启
服务端收到:Netty The Sinper
服务端收到:Netty The Sinper
服务端收到:www.itstack.org
服务端收到:www.itstack.org
服务端收到:您好,您也在学习Netty吗?
服务端收到:是的!一起学习吧!
服务端收到:嗯,到群里来吧5360392
服务端收到:好的,么么大

4、客户端输出截图:


六、温馨提示

大家可以到链接http://download.csdn.net/detail/l1028386804/9753030下载完整的基于Netty5.0高级案例NettyWebsocket的源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值