netty helloworld

一切從 helloworld 開始

1.從 helloworld 開始

主函數部分

主函數部分,設置接收鏈接的 nio 池。處理事件的 nio 池。
輸入任意字符退出。

HelloServer

package com.yhy;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.util.Scanner;

public class HelloServer {
    private int PORT = 8080;
    //接收請求的 nio 池
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    //接收數據的 nio 池
    private EventLoopGroup workerGroup = new NioEventLoopGroup();


    public static void main( String args[] ){
        HelloServer helloServer = new HelloServer();
        try {
            helloServer.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Scanner in=new Scanner(System.in); //使用Scanner類定義對象
        in.next();

        helloServer.stop();
    }

    public void start() throws InterruptedException {
        ServerBootstrap b = new ServerBootstrap();
        //指定接收鏈接的 NioEventLoop,和接收數據的 NioEventLoop
        b.group(bossGroup, workerGroup);
        //指定server使用的 channel
        b.channel(NioServerSocketChannel.class);
        //初始化處理請求的編解碼,處理響應類等
        b.childHandler(new HelloServerInitializer());
        // 服務器綁定端口監聽
        b.bind(PORT).sync();
    }

    public void stop(){
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

初始化類

netty server 在啓動的時候需要在初始化類裏設置必要的參數。
主要初始化業務處理之前的解碼器,業務處理之後的編碼器,以及業務處理類。
這裏爲了簡單起見我們使用 StringEncoder 和 StringDecoder 做編解碼器。

package com.yhy;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


public class HelloServerInitializer extends ChannelInitializer<SocketChannel>{
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        // 以("\n")爲結尾分割的 解碼器
        pipeline.addLast("framer",
                new DelimiterBasedFrameDecoder(2048, Delimiters.lineDelimiter()));

        //字符串編碼和解碼
        pipeline.addLast("decoder",new StringDecoder());
        pipeline.addLast("encoder",new StringEncoder());

        // 自己的邏輯Handler
        pipeline.addLast("handler",new HelloServerHandler());
    }
}

業務處理類

我們在上面初始化服務的時候指定了業務處理類。下面就是業務處理類。指定要處理哪些事件。
一般情況下我們只要繼承 SimpleChannelInboundHandler 類。最常見的情況是,你的應用 程序會利用一個ChannelHandler來接收解碼消息, 並對該數據應用業務邏輯。 要創建一個這樣 的 ChannelHandler, 你只需要擴展基類 SimpleChannel-InboundHandler, 其中 T 是你要處理的消息的 Java 類型。在這個 ChannelHandler 中,你將需要重寫基類的一個 或者 多個方法,並且獲取一個到 ChannelHandlerContext 的引用, 這個引用將作爲輸入參數傳遞 給 ChannelHandler 的所有方法。

package com.yhy;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class HelloServerHandler extends SimpleChannelInboundHandler<String> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //處理消息
        System.out.println("channelRead0" + ctx.channel().remoteAddress() + ":" + msg);
        //返回消息
        ctx.channel().writeAndFlush("recvied message");
    }

    //客戶端鏈接的時候觸發
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelRegistered:"+ctx.channel().remoteAddress());
    }

    //客戶端斷開鏈接的時候觸發
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelUnregistered:"+ctx.channel().remoteAddress());
    }

    //客戶端鏈接上來的時候觸發
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelActive:"+ctx.channel().remoteAddress());
    }

    //客戶端斷開鏈接的時候觸發
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelInactive:"+ctx.channel().remoteAddress());
    }

    //完成一次讀操作知 channle 的都數據都讀完了(可讀字節數爲0),區別channelRead0() 這個是每次從channel讀到數據的時候都觸發
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelReadComplete:"+ctx.channel().remoteAddress());
    }

    //用戶自定義的觸發,後面超時無數據會用到
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        System.out.println("userEventTriggered:"+ctx.channel().remoteAddress());
    }

    //Channel的可寫狀態變化通知事件
    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelWritabilityChanged:"+ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("exceptionCaught:"+ctx.channel().remoteAddress());
    }
}

各種事件的解釋

channelRegistered: Invoked when a Channel is registered to its EventLoop and is able to handle I/O.
channelUnregistered: Invoked when a Channel is deregistered from its EventLoop and cannot handle any I/O.
channelActive: Invoked when a Channel is active; the Channel is connected/bound and ready.
channelInactive: Invoked when a Channel leaves active state and is no longer connected to its remote peer.
channelReadComplete: Invoked when a read operation on the Channel has completed.
channelRead: Invoked if data are read from the Channel.
channelWritabilityChanged: Invoked when the writability state of the Channel changes. The user can ensure writes are not done too fast (with risk of an OutOfMemoryError) or can resume writes when the Channel becomes writable again.Channel.isWritable() can be used to detect the actual writability of the channel. The threshold for writability can be set via Channel.config().setWriteHighWaterMark() and Channel.config().setWriteLowWaterMark().
userEventTriggered(…): Invoked when a user calls Channel.fireUserEventTriggered(…) to pass a pojo through the ChannelPipeline. This can be used to pass user specific events through the ChannelPipeline and so allow handling those events.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章