【Netty官方文檔翻譯】Getting Started

在這一章節(jié)里瓢湃,會以一個簡單的例子來展示Netty的核心結(jié)構(gòu),來讓你快速入門析藕。當你看完這一章節(jié)之后召廷,你應(yīng)該可以寫一個客戶端和服務(wù)端。
  如果你更喜歡自頂向下的學習方式,你可能想要從章節(jié)2[結(jié)構(gòu)概覽]開始竞慢,然后再回到這里先紫。

Before Getting Started 在開始之前

要運行這個章節(jié)的例子的話,最低的要求是最新版的Netty和jdk1.6或以上筹煮。最新版本的Netty的下載地址下載遮精。jdk略。
  當你在閱讀的時候败潦,你可能會對這一章節(jié)介紹的類有更多的問題本冲。請隨時查詢API文檔。為了你的方便劫扒,所有的類名都連接到在線的API文檔檬洞。
如果有錯誤的信息,請不要猶豫沟饥,聯(lián)系Netty的社區(qū)添怔。

Writing a Discard Server 寫一個拋棄信息的服務(wù)器

最簡單的協(xié)議不是"Hello, World"而是DISCARD。這是一個對所有收到的數(shù)據(jù)不做任何響應(yīng)的協(xié)議贤旷。
  為了實現(xiàn)DISCARD協(xié)議广料,你需要做的事情就是忽略所有收到的數(shù)據(jù)。讓我們直接從處理I/O時間的handler的實現(xiàn)開始吧幼驶。

package io.netty.example.discard;

import io.netty.buffer.ByteBuf;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * Handles a server-side channel.
 */
public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
        // Discard the received data silently.
        ((ByteBuf) msg).release(); // (3)
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

1.DiscardServerHandler繼承了實現(xiàn)了ChannelInboundHandler
ChannelInboundHandlerAdapter艾杏。ChannelInboundHandler提供了各種你可以重寫的事件處理方法。就現(xiàn)在來說县遣,只需要繼承 ChannelInboundHandlerAdapter就夠了糜颠,不需要自己實現(xiàn)handler接口。
2.我們重寫了channelRead()事件處理方法萧求。當收到消息的時候這個方法會被調(diào)用其兴。在這個例子中,消息的類型是 ByteBuf夸政。
3.為了實現(xiàn)DISCARD協(xié)議元旬,這個handler必須忽略收到的消息。ByteBuf
是一個通過release()方法釋放的引用計數(shù)的對象守问。請注意匀归,這個handler方法的責任就是使任何引用計數(shù)對象通過到達下一個handler。通常耗帕,channelRead()處理方法會像下面這樣實現(xiàn):

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    try {
        // Do something with msg
    } finally {
        ReferenceCountUtil.release(msg);
    }
}

4.當Netty拋出一個I/O異衬露耍或者handler實現(xiàn)方法拋出一個異常的時候exceptionCaught()事件處理方法就會被調(diào)用。大多數(shù)情況下仿便,被catch到的異常應(yīng)該被記錄日志体啰,它所關(guān)聯(lián)的channel也應(yīng)該被關(guān)閉攒巍,不過這個方法的具體實現(xiàn)可以根據(jù)你的情況而定。例如荒勇,你可能會在連接關(guān)閉之前發(fā)送一個包含錯誤碼的響應(yīng)消息柒莉。

到目前為止一切順利,我們已經(jīng)實現(xiàn)了一半DISCARD服務(wù)器了沽翔。剩下的就是寫main()方法來啟動DiscardServerHandler兢孝。

package io.netty.example.discard;
    
import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
    
/**
 * Discards any incoming data.
 */
public class DiscardServer {
    
    private int port;
    
    public DiscardServer(int port) {
        this.port = port;
    }
    
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3)
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5)
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
    
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    
    public static void main(String[] args) throws Exception {
        int port;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        } else {
            port = 8080;
        }
        new DiscardServer(port).run();
    }
}

1.NioEventLoopGroup
是一個處理I/O操作的多線程事件循環(huán)器。Netty提供了多種EventLoopGroup實現(xiàn)用來處理不同的傳輸仅偎。在這個例子里跨蟹,我們實現(xiàn)一個服務(wù)端的應(yīng)用,所以會用到兩個NioEventLoopGroup哨颂。第一個被稱為"boss"喷市,它接收到來的連接相种。第二個被稱為"worker"威恼,用來處理已經(jīng)被建立的連接,一旦boss接收了連接寝并,他就會把連接注冊到worker上箫措。具體會使用到多少線程,線程怎么映射到已經(jīng)創(chuàng)建了的Channel上的取決于EventLoopGroup
的實現(xiàn)衬潦,甚至可以用構(gòu)造函數(shù)來配置斤蔓。
2.ServerBootstrap
是一個用來啟動服務(wù)器的輔助類。你也可以直接用Channel
來啟動服務(wù)器镀岛。然而弦牡,請注意這是一個繁瑣的過程,在大多數(shù)情況下漂羊,你都不需要做驾锰。
3.這里,我們指定使用 NioServerSocketChannel來初始化一個新的Channel
來接收到來的連接走越。
4.被指定的處理器會一直被用來處理新接收的Channel椭豫。ChannelInitializer
是一個用來幫助我們配置新Channel
的特別handler。最常見的情況是你想要通過增加譬如DiscardServerHandler的handler實現(xiàn)給新的Channel
配置 ChannelPipeline最終實現(xiàn)你的網(wǎng)絡(luò)應(yīng)用旨指。當你的應(yīng)用變得復(fù)雜時赏酥,你可能會增加更多的handler到pipeline,然后提取提取一個匿名類到最上層谆构。
5.你也可以給Channel的實現(xiàn)設(shè)置參數(shù)裸扶,我們正在寫一個TCP/IP的服務(wù)器,所以我們可以設(shè)置socket選項為tcpNpDelaykeepAlive搬素。請聯(lián)系 ChannelOption
和特定的ChannelConfig
實現(xiàn)的API文檔來獲取一個被支持的ChannelOption的概覽呵晨。
6.你有沒有注意到option()childOption()瞬项?前者是為了NioServerSocketChannel接收連接,后者是為了被parent ServerChannel
接收的Channel何荚,在這里囱淋, ServerChannel
指的是 NioServerSocketChannel
7.現(xiàn)在我們準備好了餐塘。剩下的就是去綁定端口號妥衣,然后啟動服務(wù)器。這里戒傻,我們綁定8080.你現(xiàn)在可以調(diào)用bind()方法隨意多的次數(shù)(使用不同的綁定地址)税手。

祝賀!你已經(jīng)完成了你的第一個Netty服務(wù)器需纳。

Looking into the Received Data 查看收到的數(shù)據(jù)

現(xiàn)在我們已經(jīng)寫了我們的第一個服務(wù)器芦倒,我們需要測試它是不是真的能工作。最簡單的方法就是用telnet命令不翩。例如兵扬,你可以輸入telnet localhost 8080,然后輸入一些東西口蝠。

然而器钟,這樣我們就能說這個服務(wù)器能正常工作了嗎?我們不知道妙蔗,因為他是個丟棄數(shù)據(jù)的服務(wù)器傲霸。你得不到任何的響應(yīng)。為了證明它真的可以正常工作眉反,然我們修改一下服務(wù)器昙啄,讓他打印出他收到的消息。

我們已經(jīng)知道channelRead()方法會在接收到數(shù)據(jù)的時候被調(diào)用寸五。讓我們在channelRead()方法里加一點代碼:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ByteBuf in = (ByteBuf) msg;
    try {
        while (in.isReadable()) { // (1)
            System.out.print((char) in.readByte());
            System.out.flush();
        }
    } finally {
        ReferenceCountUtil.release(msg); // (2)
    }
}

1.這個低效率的循環(huán)可以被簡化成System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))
2.你可以用in.release替換這里

如果你再次運行telnet命令梳凛,你就會看到服務(wù)器打印出了他剛收到的消息。

源代碼在io.netty.example.discard

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末播歼,一起剝皮案震驚了整個濱河市伶跷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秘狞,老刑警劉巖叭莫,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烁试,居然都是意外死亡雇初,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門减响,熙熙樓的掌柜王于貴愁眉苦臉地迎上來靖诗,“玉大人郭怪,你說我怎么就攤上這事】伲” “怎么了鄙才?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長促绵。 經(jīng)常有香客問我攒庵,道長,這世上最難降的妖魔是什么败晴? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任浓冒,我火速辦了婚禮,結(jié)果婚禮上尖坤,老公的妹妹穿的比我還像新娘稳懒。我一直安慰自己,他們只是感情好慢味,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布场梆。 她就那樣靜靜地躺著,像睡著了一般贮缕。 火紅的嫁衣襯著肌膚如雪辙谜。 梳的紋絲不亂的頭發(fā)上俺榆,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天感昼,我揣著相機與錄音,去河邊找鬼罐脊。 笑死定嗓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的萍桌。 我是一名探鬼主播宵溅,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼上炎!你這毒婦竟也來了恃逻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤藕施,失蹤者是張志新(化名)和其女友劉穎寇损,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裳食,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡矛市,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了诲祸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浊吏。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡而昨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出找田,到底是詐尸還是另有隱情歌憨,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布墩衙,位于F島的核電站躺孝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏底桂。R本人自食惡果不足惜植袍,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望籽懦。 院中可真熱鬧于个,春花似錦、人聲如沸暮顺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捶码。三九已至羽氮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惫恼,已是汗流浹背档押。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祈纯,地道東北人令宿。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像腕窥,于是被迫代替她去往敵國和親粒没。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359