基于websocket的netty框架的理解

Netty是什么?

基于Java NIO的非阻塞网络框架,Netty是一个NIO client-server(客户端服务器)框架,异步非阻塞是其主要的特性,使用Netty可以快速开发网络应用,例如服务器和客户端协议。
Java NIO教程:http://ifeve.com/overview/
Netty官方用户指南:http://ifeve.com/netty5-user-guide/

可以用来干什么?

高实时性,高并发性的网络应用,比如: 即时聊天系统,网游,股票分析等等;支持websocket,可以用来实现相关的网页聊天系统。

websocket是什么?

WebSocket协议被设计来取代现有的使用HTTP作为传输层的双向通信技术,服务器根据http header识别是否一个websocket请求,如果是,则将请求升级为一个websocket连接,握手成功后就进入双向长连接的数据传输阶段,即,

实例(以使用websocket协议的例子):

NettyServer:

public class NettyServer {
    public void run(final int port) throws InterruptedException {
        /*
         * Boss线程:由这个线程池提供的线程是boss种类的,用于创建、连接、绑定socket, (有点像门卫,,
         * 然后把这些socket传给worker线程池。在服务器端每个监听的socket都 有一个boss线 程来处理。
         * 在客户端,只有一个boss线程来处理所有的socket。
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        /*
         * Worker线程:Worker线 程执行所有的异步I/O,即处理操作
         */
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // ServerBootstrap 启动NIO服务的辅助启动类,负责初始话netty服务器,并且开始监听端口的socket请求
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
            // 设置非阻塞,用它来建立新accept的连接,用于构造serversocketchannel的工厂类
                    .channel(NioServerSocketChannel.class)
            //WebsocketHandlerImp 对出入的数据进行的业务操作,其继承ChannelInitializer
                    .childHandler(new WebsocketHandlerImp());
            System.out.println("ok!!~~~~");
            ChannelFuture future = b.bind(port).sync();//绑定本地端口并同步等待完成,future是一个通道状态类
            future.channel().closeFuture().sync();
        } finally {//往下就是异常时的关闭了
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            System.out.println("down!!~~~~");
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        NettyServer server = new NettyServer();
        try {
            server.run(8080);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

WebsocketHandlerImp:

public class WebsocketHandlerImp extends ChannelInitializer<SocketChannel>{
    protected void initChannel(SocketChannel ch) throws Exception {

        ch.pipeline().addLast(new HttpServerCodec());//http解码,websocket是以http发起请求的
        ch.pipeline().addLast(new HttpObjectAggregator(65536));//HttpObjectAggregator会把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse
        ch.pipeline().addLast(new ChunkedWriteHandler());//这个?。。啥意思
        ch.pipeline().addLast(new WebsocketHandler());//WebsocketHandler 自己定义的类,用以处理传过来的数据
    }
}

WebsocketHandler:

public class WebsocketHandler extends SimpleChannelInboundHandler<Object>{

    private WebSocketServerHandshaker handshaker;
    protected void messageReceived(ChannelHandlerContext ctx, Object msg)
            throws Exception {
<span style="white-space:pre">      </span>system.out.println(msg);//msg输出看看是啥
        if(msg instanceof FullHttpRequest){//处理http握手请求
            handleHttpRequest(ctx,(FullHttpRequest)msg);
        }else if(msg instanceof WebSocketFrame){//websocket请求
            handleWebSocketFrame(ctx,(WebSocketFrame)msg);
        }else{
            //其他请求
        }
    }
    //处理http的握手请求
     private void handleHttpRequest(ChannelHandlerContext ctx,
                FullHttpRequest req) throws Exception {
            // 如果HTTP解码失败,返回HTTP异常,如果不是websocket,异常返回
            if (!req.getDecoderResult().isSuccess()
                || (!"websocket".equals(req.headers().get("Upgrade")))) {
                sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
                    BAD_REQUEST));
                return;
            }

            // 构造握手响应返回,本机测试
            WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                     "ws://"+req.headers().get(HttpHeaders.Names.HOST), null, false);
            handshaker = wsFactory.newHandshaker(req);
            if (handshaker == null) {
                WebSocketServerHandshakerFactory
                    .sendUnsupportedWebSocketVersionResponse(ctx.channel());
            } else {
                handshaker.handshake(ctx.channel(), req);//返回response
            }
     }

     //websocket数据交互
     private void handleWebSocketFrame(ChannelHandlerContext ctx,
                WebSocketFrame frame) {

            // 判断是否是关闭链路的指令
            if (frame instanceof CloseWebSocketFrame) {
                handshaker.close(ctx.channel(),
                    (CloseWebSocketFrame) frame.retain());
                return;
            }
            // 判断是否是Ping消息
            if (frame instanceof PingWebSocketFrame) {
                ctx.channel().write(
                    new PongWebSocketFrame(frame.content().retain()));
                return;
            }
            //文本消息,不支持二进制消息
            if (frame instanceof TextWebSocketFrame) {
            // 返回应答消息
            String request = ((TextWebSocketFrame) frame).text();
            ctx.channel().writeAndFlush(
                new TextWebSocketFrame(request
                    + " , 欢迎使用Netty WebSocket服务,现在时刻:"
                    + new java.util.Date().toString()));
            }
        }
     //握手请求不成功时返回的应答
     private static void sendHttpResponse(ChannelHandlerContext ctx,
                FullHttpRequest req, FullHttpResponse res) {
            // 返回应答给客户端
            if (res.getStatus().code() != 200) {
                ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
                    CharsetUtil.UTF_8);
                res.content().writeBytes(buf);
                buf.release();
                setContentLength(res, res.content().readableBytes());
            }
            // 如果是非Keep-Alive,关闭连接
            ChannelFuture f = ctx.channel().writeAndFlush(res);
            if (!isKeepAlive(req) || res.getStatus().code() != 200) {
                f.addListener(ChannelFutureListener.CLOSE);
            }
        }
    //异常出错
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
        }
}

其中:来着客户端的握手请求形式:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

来自服务器的握手看起来像如下形式:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
以下msg第一次输出为以上的来着客户端的握手请求形式http报头
之后输出形如:TextWebSocketFrame(data: UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 6))
关闭页面后:CloseWebSocketFrame(data: UnpooledUnsafeDirectByteBuf(ridx: 0, widx: 2, cap: 2))

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值