Netty之——基于Netty5.0高级案例NettyWebsocket
来源:互联网 发布:java调用外部http接口 编辑:程序博客网 时间:2024/06/06 04:58
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/55026558
今天,是年后第一次发表博文,今天就给大家带来一篇有关netty的文章吧,好了,我们直接进入主题。
一、前言介绍
本案例主要介绍如何使用Netty开发websocket。
二、环境需求
1、jdk1.7
2、Eclipse
3、Netty5.0
4、支持websocket的浏览器[火狐]
三、工程截图
四、代码部分
1、服务端
Global.javapackage com.itstack.netty.common;import io.netty.channel.group.ChannelGroup;import io.netty.channel.group.DefaultChannelGroup;import io.netty.util.concurrent.GlobalEventExecutor;public class Global {public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);}ChildChannelHandler.java
package com.itstack.netty.websocket;import io.netty.channel.ChannelInitializer;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.HttpServerCodec;import io.netty.handler.stream.ChunkedWriteHandler;public class ChildChannelHandler extends ChannelInitializer<SocketChannel>{@Overrideprotected void initChannel(SocketChannel e) throws Exception {e.pipeline().addLast("http-codec",new HttpServerCodec());e.pipeline().addLast("aggregator",new HttpObjectAggregator(65536));e.pipeline().addLast("http-chunked",new ChunkedWriteHandler());e.pipeline().addLast("handler",new MyWebSocketServerHandler());}}MyWebSocketServerHandler.java
package com.itstack.netty.websocket;import java.util.Date;import java.util.logging.Level;import java.util.logging.Logger;import com.itstack.netty.common.Global;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.DefaultFullHttpRequest;import io.netty.handler.codec.http.DefaultFullHttpResponse;import io.netty.handler.codec.http.FullHttpRequest;import io.netty.handler.codec.http.HttpResponseStatus;import io.netty.handler.codec.http.HttpVersion;import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;import io.netty.handler.codec.http.websocketx.WebSocketFrame;import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;import io.netty.util.CharsetUtil;public class MyWebSocketServerHandler extends SimpleChannelInboundHandler<Object> { private static final Logger logger = Logger .getLogger(WebSocketServerHandshaker.class.getName()); private WebSocketServerHandshaker handshaker; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 添加 Global.group.add(ctx.channel()); System.out.println("客户端与服务端连接开启"); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { // 移除 Global.group.remove(ctx.channel()); System.out.println("客户端与服务端连接关闭"); } @Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { handleHttpRequest(ctx, ((FullHttpRequest) msg)); } else if (msg instanceof WebSocketFrame) { handlerWebSocketFrame(ctx, (WebSocketFrame) msg); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // 判断是否关闭链路的指令 if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame .retain()); } // 判断是否ping消息 if (frame instanceof PingWebSocketFrame) { ctx.channel().write( new PongWebSocketFrame(frame.content().retain())); return; } // 本例程仅支持文本消息,不支持二进制消息 if (!(frame instanceof TextWebSocketFrame)) { System.out.println("本例程仅支持文本消息,不支持二进制消息"); throw new UnsupportedOperationException(String.format( "%s frame types not supported", frame.getClass().getName())); } // 返回应答消息 String request = ((TextWebSocketFrame) frame).text(); System.out.println("服务端收到:" + request); if (logger.isLoggable(Level.FINE)) { logger .fine(String.format("%s received %s", ctx.channel(), request)); } TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString() + ctx.channel().id() + ":" + request); // 群发 Global.group.writeAndFlush(tws); // 返回【谁发的发给谁】 // ctx.channel().writeAndFlush(tws); } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { if (!req.getDecoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( "ws://localhost:7397/websocket", null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory .sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } } private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, DefaultFullHttpResponse res) { // 返回应答给客户端 if (res.getStatus().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); } // 如果是非Keep-Alive,关闭连接 ChannelFuture f = ctx.channel().writeAndFlush(res); if (!isKeepAlive(req) || res.getStatus().code() != 200) { f.addListener(ChannelFutureListener.CLOSE); } } private static boolean isKeepAlive(FullHttpRequest req) { return false; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); }}NettyServer.java
package com.itstack.netty.websocket;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.Channel;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.nio.NioServerSocketChannel;public class NettyServer { public static void main(String[] args) { new NettyServer().run(); } public void run(){ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workGroup); b.channel(NioServerSocketChannel.class); b.childHandler(new ChildChannelHandler()); System.out.println("服务端开启等待客户端连接 ... ..."); Channel ch = b.bind(7397).sync().channel(); ch.closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); }finally{ bossGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } } }
2、客户端
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> </head> </head> <script type="text/javascript"> var socket; if(!window.WebSocket){ window.WebSocket = window.MozWebSocket; } if(window.WebSocket){ socket = new WebSocket("ws://localhost:7397/websocket"); socket.onmessage = function(event){ var ta = document.getElementById('responseText'); ta.value += event.data+"\r\n"; }; socket.onopen = function(event){ var ta = document.getElementById('responseText'); ta.value = "打开WebSoket 服务正常,浏览器支持WebSoket!"+"\r\n"; }; socket.onclose = function(event){ var ta = document.getElementById('responseText'); ta.value = ""; ta.value = "WebSocket 关闭"+"\r\n"; }; }else{ alert("您的浏览器不支持WebSocket协议!"); } function send(message){ if(!window.WebSocket){return;} if(socket.readyState == WebSocket.OPEN){ socket.send(message); }else{ alert("WebSocket 连接没有建立成功!"); } } </script> <body> <form onSubmit="return false;"> <input type = "text" name="message" value="Netty The Sinper"/> <br/><br/> <input type="button" value="发送 WebSocket 请求消息" onClick="send(this.form.message.value)"/> <hr color="blue"/> <h3>服务端返回的应答消息</h3> <textarea id="responseText" style="width: 1024px;height: 300px;"></textarea> </form> </body> </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的源代码
1 0
- Netty之——基于Netty5.0高级案例NettyWebsocket
- 基于Netty5.0高级案例一之NettyWebsocket
- 基于Netty5.0高级案例一之NettyWebsocket
- 基于Netty5.0中级案例一之Netty与Web
- 基于Netty5.0高级案例之请求响应同步通信
- 基于Netty5.0高级案例二之WebSocket中关于使用ProtoBuf传输数据介绍js部分
- 基于Netty5.0入门案例一之NettyServer
- 基于Netty5.0入门案例二之NettyServer接收数据
- 基于Netty5的RPC架构笔记4之案例讲解
- 基于Netty5.0案例八服务端心跳包
- netty5.0之EventLoop
- Netty5用户手册之六:netty核心之ChannelHandler用法详解
- Netty5用户手册之二:使用netty实现Discard服务器程序
- Netty5用户手册之三:使用netty实现EchoServer程序
- netty5.0之SingleThreadEventLoop & NioEventLoop
- netty5.0之Future和Promise
- netty5.0之 ChannelPipeline和ChannelHandler
- Netty5用户手册之四:使用netty实现Timer客户端和服务端程序
- html5学习笔记(六)
- ubuntu 搭建 ftp
- hibernate4配置文件
- html5学习笔记(七)
- Python学习:纠错笔记:详解os.removedirs(path)的正确用法
- Netty之——基于Netty5.0高级案例NettyWebsocket
- Python 网络抓取和文本挖掘 - 3 XPath
- c指针练习——学生管理单链表
- 【算法】线段树与树状数组
- 51.样式和主题
- 线性代数-【2-1】矩阵及其运算
- C++学习一静态成员与静态成员函数
- 01-iOS蓝牙开发简介
- 02-iOS蓝牙连接流程介绍