intellij netty客戶端和服務(wù)端

Netty是一款異步的事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,支持快速地開(kāi)發(fā)可維護(hù)的高性能的面向協(xié)議的服務(wù)器和客戶端。 ----摘自《Netty in action》

如果對(duì)于Java網(wǎng)絡(luò)編程不是很熟悉的同學(xué),在第一遍看書(shū)的時(shí)候,心里肯定是一個(gè)大寫(xiě)的懵 - -,所以老老實(shí)實(shí)的照著教程寫(xiě)了第一個(gè)netty的客戶端和服務(wù)端,并思考了netty的核心組件。

netty的核心組件:

  1. Channel (渠道,出入站數(shù)據(jù)的載體)
  2. 回調(diào)
  3. Future
  4. 事件和ChannelHandler

新建項(xiàng)目

  1. 通過(guò)file -> new -> project -> maven
    新建一個(gè)maven項(xiàng)目,不用選擇原型,填寫(xiě)GroupId和ArtifactId,版本號(hào)默認(rèn)。
新建nettyJoin項(xiàng)目
  1. 通過(guò)file -> new -> Module 新建客戶端模塊
    GroupId和version是默認(rèn)的,artifactId可以自定義。


    客戶端模塊
  2. 同樣的方式建立服務(wù)端模塊

服務(wù)端模塊
  1. 項(xiàng)目結(jié)構(gòu)如下
項(xiàng)目結(jié)構(gòu)

添加依賴與maven插件

  1. 主pom.xml文件(最外部的)
    這里加了兩個(gè)插件,一個(gè)是maven-compiler-plugin,主要是用在項(xiàng)目編譯、打包的時(shí)候。一個(gè)是exe-maven-plugin,主要是用來(lái)執(zhí)行main函數(shù)。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.netty</groupId>
    <artifactId>nettyJoin</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>nettyClient</module>
        <module>nettyServer</module>
    </modules>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-all</artifactId>
                <version>4.1.13.Final</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <!-- put your configurations here -->
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.2.1</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>java</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
  1. nettyClient的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>nettyJoin</artifactId>
        <groupId>com.netty</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.netty</groupId>
    <artifactId>nettyClient</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>
    </dependencies>
</project>
  1. nettyServer的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>nettyJoin</artifactId>
        <groupId>com.netty</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.netty</groupId>
    <artifactId>nettyServer</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
        </dependency>
    </dependencies>
</project>

注:jdk、maven什么的環(huán)境變量這里就不累贅了

編寫(xiě)客戶端代碼

注:代碼都是參考《netty in action》中的例子

  1. 處理器EchoClientHandler
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext,
                                          ByteBuf byteBuf) throws Exception {
        //記錄已接收消息的轉(zhuǎn)儲(chǔ)
        System.out.println("Client received: " + byteBuf.toString(CharsetUtil.UTF_8));
    }

    /**
     * 作為一個(gè)回調(diào)函數(shù)
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //當(dāng)被通知Channel是活躍的時(shí)候,發(fā)送一條消息
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
  1. main函數(shù)
public class EchoClient {

    private int port;

    private String host;

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

    public void start() throws InterruptedException {
        //進(jìn)行事件處理分配,包括創(chuàng)建新的連接以及處理入站和出站數(shù)據(jù)
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            //創(chuàng)建Bootstrap 初始化客戶端
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host, port))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel)
                                throws Exception {
                            socketChannel.pipeline().addLast(new EchoClientHandler());
                        }
                    });

            //連接到遠(yuǎn)程節(jié)點(diǎn),阻塞等待直到連接完成
            ChannelFuture f = b.connect().sync();
            //阻塞,直到channel關(guān)閉
            f.channel().closeFuture().sync();
        } finally {
            //關(guān)閉線程池并且釋放所有的資源
            group.shutdownGracefully().sync();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        if (args.length != 2) {
            System.err.println("Usages: " + EchoClient.class.getSimpleName() + "<host><port>");
            return;
        }

        String host = args[0];
        int port = Integer.parseInt(args[1]);
        new EchoClient(port, host).start();
    }
}

編寫(xiě)服務(wù)端代碼

  1. 處理器EchoServerHandler
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    private Logger logger = Logger.getLogger("com.EchoServerHandler");

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
        //將接收到的消息寫(xiě)給發(fā)送者,而不沖刷出站消息
        ctx.write(in);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //將未決消息沖刷到遠(yuǎn)程節(jié)點(diǎn),并且關(guān)閉該channel
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
  1. main函數(shù)
public class EchoServer {

    private int port;

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

    public static void main(String[] args) throws InterruptedException {
        if (args.length != 1) {
            System.err.println("Usages: " + EchoServer.class.getSimpleName() + "<port>");
        }

        int port = Integer.parseInt(args[0]);
        new EchoServer(port).start();
    }

    /**
     * 啟動(dòng)方法
     *
     * @throws InterruptedException
     */
    public void start() throws InterruptedException {
        final EchoServerHandler serverHandler = new EchoServerHandler();

        //1創(chuàng)建EventLoopGroup 用來(lái)接收和處理新的連接
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            //2 創(chuàng)建ServerBootstrap
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    //3 制定所使用的NIO傳輸channel
                    .channel(NioServerSocketChannel.class)
                    //4 使用制定的端口設(shè)置套接字地址
                    .localAddress(new InetSocketAddress((port)))
                    //5 添加一個(gè)EchoServerHandler到子channel的ChannelPipeLine
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel socketChannel)
                                throws Exception {
                            //EchoServerHandler被標(biāo)注為@Shareable,所以我們可以總是使用同樣的實(shí)例
                            socketChannel.pipeline().addLast(serverHandler);
                        }
                    });

            //6 異地綁定服務(wù)器;調(diào)用sync方法阻塞等待直到綁定完成
            ChannelFuture f = b.bind().sync();
            //7 獲取channel的closeFuture,并且阻塞當(dāng)前線程直到它完成
            f.channel().closeFuture().sync();
        } finally {
            //8 關(guān)閉EventLoopGroup釋放所有的資源
            group.shutdownGracefully().sync();
        }
    }
}

目錄結(jié)構(gòu)

目錄結(jié)構(gòu)

運(yùn)行項(xiàng)目

現(xiàn)在本地將客戶端和服務(wù)端的代碼打包,進(jìn)入兩個(gè)模塊的根目錄,運(yùn)行mvn clean package即可。

  1. 項(xiàng)目打包


    客戶端打包
打包成功
  1. 運(yùn)行服務(wù)端代碼
    進(jìn)入服務(wù)端模塊的根目錄,運(yùn)行下面的命令,后面跟的是main函數(shù)和入?yún)?/li>
mvn exec:java -Dexec.mainClass="com.EchoServer" -Dexec.args="9999"
運(yùn)行結(jié)果

服務(wù)器啟動(dòng)完畢,并等待連接。

  1. 啟動(dòng)客戶端
    進(jìn)入客戶端模塊的根目錄,運(yùn)行下面的命令,后面跟的是main函數(shù)和入?yún)?/li>
mvn exec:java -Dexec.mainClass="com.EchoClient" -Dexec.args="127.0.0.1 9999"
客戶端啟動(dòng)成功

圖中右邊的是客戶端命令行,可以看到已經(jīng)打印出“Client received: Netty rocks!”,服務(wù)端也正常接收到消息,并打印出了“Server received: Netty rocks!”。

小結(jié)

可能在代碼編寫(xiě)過(guò)程中,或是編譯打包的過(guò)程中,都會(huì)碰到各種錯(cuò)誤,因?yàn)榇蠹业倪\(yùn)行環(huán)境都各不相同,碰到問(wèn)題的同學(xué)可以在下面留言,也可以自行百度。
這也是我第一次接觸netty,才看了書(shū)的前兩章,接下來(lái)也會(huì)把自己的總結(jié)、感悟?qū)懺趎etty上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評(píng)論 6 342
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評(píng)論 25 709
  • 越南南部海岸線最東端的地方 有一個(gè)恬靜的海邊小城---芽莊Nha Trang 都說(shuō)每座城有每座城的標(biāo)簽 在這個(gè)擁有...
    candy_小微閱讀 529評(píng)論 0 0
  • 圖標(biāo)終結(jié)者 隨著下載的軟件越來(lái)越多,圖標(biāo)管理已經(jīng)是一個(gè)難題了!圖標(biāo)太多,很難管理,要打開(kāi)某個(gè)應(yīng)用的時(shí)候眼花繚亂。所...
    CSU_IceLee閱讀 322評(píng)論 0 2

友情鏈接更多精彩內(nèi)容