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.java

package 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
原创粉丝点击