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

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

如果對(duì)于Java網(wǎng)絡(luò)編程不是很熟悉的同學(xué),在第一遍看書的時(shí)候苛白,心里肯定是一個(gè)大寫的懵 - -娃豹,所以老老實(shí)實(shí)的照著教程寫了第一個(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)目,不用選擇原型躏率,填寫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)境變量這里就不累贅了

編寫客戶端代碼

注:代碼都是參考《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();
    }
}

編寫服務(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));
        //將接收到的消息寫給發(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é)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弛矛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子比然,更是在濱河造成了極大的恐慌丈氓,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件强法,死亡現(xiàn)場(chǎng)離奇詭異万俗,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)饮怯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門闰歪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蓖墅,你說(shuō)我怎么就攤上這事库倘。” “怎么了置媳?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵于樟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拇囊,道長(zhǎng),這世上最難降的妖魔是什么靶橱? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任寥袭,我火速辦了婚禮路捧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘传黄。我一直安慰自己杰扫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布膘掰。 她就那樣靜靜地躺著章姓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪识埋。 梳的紋絲不亂的頭發(fā)上凡伊,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音窒舟,去河邊找鬼系忙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惠豺,可吹牛的內(nèi)容都是我干的银还。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼洁墙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蛹疯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起热监,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苍苞,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后狼纬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羹呵,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年疗琉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冈欢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盈简,死狀恐怖凑耻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柠贤,我是刑警寧澤香浩,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站臼勉,受9級(jí)特大地震影響邻吭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宴霸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一囱晴、第九天 我趴在偏房一處隱蔽的房頂上張望膏蚓。 院中可真熱鬧,春花似錦畸写、人聲如沸驮瞧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)论笔。三九已至,卻和暖如春千所,著一層夾襖步出監(jiān)牢的瞬間狂魔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工真慢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毅臊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓黑界,卻偏偏與公主長(zhǎng)得像管嬉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朗鸠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

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