基於Netty的高性能RPC框架-Dubbo

Netty概述:
1、netty是基於Java NIO的網絡應用框架,client-server框架
2、Netty是一個高性能、異步事件驅動的NIO框架,它提供了對TCP、UDP和文件傳輸的支持,
作爲一個異步NIO框架,Netty的所有IO操作都是異步非阻塞的,
通過Future-Listener機制,用戶可以方便的主動獲取或者通過通知機制獲得IO操作結果。
3、作爲當前最流行的NIO框架,Netty在互聯網領域、大數據分佈式計算領域、遊戲行業、通信行業等獲得了廣泛的應用,
一些業界著名的開源組件也基於Netty的NIO框架構建。


Netty創建步驟:
NIO通訊服務端步驟:
1、創建ServerSocketChannel,爲它配置非阻塞模式
2、綁定監聽,配置TCP參數,錄入backlog大小等
3、創建一個獨立的IO線程,用於輪詢多路複用器Selector
4、創建Selector,將之前的ServerSocketChannel註冊到Selector上,並設置監聽標識位SelectionKey.ACCEPT
5、啓動IO線程,在循環體中執行Selector.select()方法,輪詢就緒的通道
6、當輪詢到處於就緒的通道時,需要進行判斷操作位,如果是ACCEPT狀態,說明是新的客戶端介入,則調用accept方法接受新的客戶端。
7、設置新接入客戶端的一些參數,並將其通道繼續註冊到Selector之中。設置監聽標識等
8、如果輪詢的通道操作位是READ,則進行讀取,構造Buffer對象等
9、更細節的還有數據沒發送完成繼續發送的問題

.在Netty中包含下面幾個主要的組件:
Bootstrap:netty的組件容器,用於把其他各個部分連接起來;如果是TCP的Server端,則爲ServerBootstrap.
Channel:代表一個Socket的連接
EventLoopGroup:一個Group包含多個EventLoop,可以理解爲線程池
EventLoop:處理具體的Channel,一個EventLoop可以處理多個Channel
ChannelPipeline:每個Channel綁定一個pipeline,在上面註冊處理邏輯handler
Handler:具體的對消息或連接的處理,有兩種類型,Inbound和Outbound。分別代表消息接收的處理和消息發送的處理。
ChannelFuture:註解回調方法

通過輪訓監聽的方式去監聽客戶端的消息,客戶端進行編碼,服務端接收的消息進行解碼。這樣一個小例子。



創建服務端:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup eventLoopGroup = null;
        try {
            //創建ServerBootstrap實例來引導綁定和啓動服務器
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            //創建NioEventLoopGroup對象來處理事件,如接受新連接、接收數據、寫數據等等
            eventLoopGroup = new NioEventLoopGroup();
            //指定通道類型爲NioServerSocketChannel,設置InetSocketAddress讓服務器監聽某個端口已等待客戶端連接。
            serverBootstrap.group(eventLoopGroup).channel(NioServerSocketChannel.class).localAddress("localhost",port).childHandler(new ChannelInitializer<Channel>() {
                //設置childHandler執行所有的連接請求
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(new EchoServerHandler());
                }
            });
            // 最後綁定服務器等待直到綁定完成,調用sync()方法會阻塞直到服務器完成綁定,然後服務器等待通道關閉,因爲使用sync(),所以關閉操作也會被阻塞。
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            System.out.println("開始監聽,端口爲:" + channelFuture.channel().localAddress());
            channelFuture.channel().closeFuture().sync();
        } finally {
            eventLoopGroup.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoServer(20000).start();
    }

}
服務端監聽器:package nio.netty.demo.EchoServer;


        import io.netty.buffer.ByteBuf;
        import io.netty.buffer.Unpooled;
        import io.netty.channel.ChannelFutureListener;
        import io.netty.channel.ChannelHandlerContext;
        import io.netty.channel.ChannelInboundHandlerAdapter;

        import java.util.Date;

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
            throws Exception {
        System.out.println("server 讀取數據……");
        //讀取數據
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("接收客戶端數據:" + body);
        //向客戶端寫數據
        System.out.println("server向client發送數據");
        String currentTime = new Date(System.currentTimeMillis()).toString();
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server 讀取數據完畢..");
        ctx.flush();//刷新後纔將數據發出到SocketChannel
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}


客戶端創建:package nio.netty.demo.EchoServer;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
//xx
import java.net.InetSocketAddress;
//aa
public class EchoClient {

    private final String host;
    private final int port;

    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup nioEventLoopGroup = null;
        try {
            //創建Bootstrap對象用來引導啓動客戶端
            Bootstrap bootstrap = new Bootstrap();
            //創建EventLoopGroup對象並設置到Bootstrap中,EventLoopGroup可以理解爲是一個線程池,這個線程池用來處理連接、接受數據、發送數據
            nioEventLoopGroup = new NioEventLoopGroup();
            //創建InetSocketAddress並設置到Bootstrap中,InetSocketAddress是指定連接的服務器地址
            bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        //添加一個ChannelHandler,客戶端成功連接服務器後就會被執行
                        @Override
                        protected void initChannel(SocketChannel ch)
                                throws Exception {
                            ch.pipeline().addLast(new EchoClientHandler());
                        }
                    });
            // • 調用Bootstrap.connect()來連接服務器
            ChannelFuture f = bootstrap.connect().sync();
            // • 最後關閉EventLoopGroup來釋放資源
            f.channel().closeFuture().sync();
        } finally {
            nioEventLoopGroup.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoClient("localhost", 20000).start();
    }

}

客戶端監聽:package nio.netty.demo.EchoServer;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;


public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    //客戶端連接服務器後被調用
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客戶端連接服務器,開始發送數據……");
        byte[] req = "小李哥上綫了!".getBytes();
        ByteBuf  firstMessage = Unpooled.buffer(req.length);
        firstMessage.writeBytes(req);
        ctx.writeAndFlush(firstMessage);
    }
    //•    從服務器接收到數據後調用  監聽服務器端接受數據的狀態
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("client 讀取server數據..");
        //服務端返回消息後
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("服務端數據爲 :" + body);

        /*ByteBuf  firstMessage = Unpooled.buffer("XXX".getBytes().length);
        firstMessage.writeBytes("XXX".getBytes());
        ctx.writeAndFlush(firstMessage);*/
    }
    //•    發生異常時被調用
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client exceptionCaught..");
        // 釋放資源
        ctx.close();
    }
}
服務端控制檯輸出:"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=57261:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;E:\mayun\rpc-svn\NettyDemo\target\classes;C:\Users\Administrator\.m2\repository\io\netty\netty-all\4.1.24.Final\netty-all-4.1.24.Final.jar" nio.netty.demo.EchoServer.EchoServer開始監聽,端口爲:/127.0.0.1:20000server 讀取數據……接收客戶端數據:小李哥上綫了!server向client發送數據server 讀取數據完畢..
客戶端控制檯輸出:
"C:\Program Files\Java\jdk1.8.0_111\bin\java" "-javaagent:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\lib\idea_rt.jar=57298:C:\installSoft\developTools\intellij idea\IntelliJ IDEA 2017.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_111\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_111\jre\lib\rt.jar;E:\mayun\rpc-svn\NettyDemo\target\classes;C:\Users\Administrator\.m2\repository\io\netty\netty-all\4.1.24.Final\netty-all-4.1.24.Final.jar" nio.netty.demo.EchoServer.EchoClient客戶端連接服務器,開始發送數據……client 讀取

更多免費技術資料可關注:annalin1203

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