翻译 Netty 4 开发人员指导-User Guide(1)

User guide for 4.x

原文

http://netty.io/wiki/user-guide-for-4.x.html



Preface

前言

The Problem

问题


Nowadays we use general purpose applications or libraries to communicate with each other. For example, we often use an HTTP client library to retrieve information from a web server and to invoke a remote procedure call via web services.

如今我们使用一般目的性的运用或者库来进行与其他程序通信。比如说,我们用http client库来获取web server上的信息,和通过 webservcie来调用一个远程的程序 。

However, a general purpose protocol or its implementation sometimes does not scale very well. It is like we don't use a general purpose HTTP server to exchange huge files, e-mail messages, and near-realtime messages such as financial information and multiplayer game data. What's required is a highly optimized protocol implementation which is dedicated to a special purpose. For example, you might want to implement an HTTP server which is optimized for AJAX-based chat application, media streaming, or large file transfer. You could even want to design and implement a whole new protocol which is precisely tailored to your need.

然而一个一般目的性的协议或者他的实现有时是难于scale的。比如说,我们不能使用一般的http server来交换很大的文件或电子邮件或者逼近实时的消息(财务数据和多人游戏的数据)。这些需要高度优化的协议的实现。这种实现是专注地为了某个特殊目的。比如你可能想实现一个http server,这个server是优化了的,是为了Ajax为基础聊天应用,流媒体,或者大文件交换。你甚至可以想设计和实现一个全新的协议,这个协议是精准的打磨出来满足你的要求。


Another inevitable case is when you have to deal with a legacy proprietary protocol to ensure the interoperability with an old system. What matters in this case is how quickly we can implement that protocol while not sacrificing the stability and performance of the resulting application.

还有一个不可以避免的难题。当你不得不处理遗留的有版权的协议来保证与陈旧的系统能过正确的通信, 这个难题会发生。而这个难题是如何快速的实现这个协议并且不会牺牲掉 使用该协议实现的应用程序的稳定性和性能。

The Solution

解决方案

The Netty project is an effort to provide an asynchronous event-driven network application framework and tooling for the rapid development of maintainable high-performance · high-scalability protocol servers and clients.

Netty 项目是已经付出的努力,提供了异步的事件驱动的一种网络应用框架,还提供了工具来快速开发高性能,性能可控,高扩张的服务器端和客户端协议。



In other words, Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients. It greatly simplifies and streamlines network programming such as TCP and UDP socket server development.

换句话来说,Netty是NIO的客户端和服务器端框架,这个框架可以快速轻松的开发应用比如服务器和客户端的协议。它极大地简化了网络编程比如说TCP,UPD的服务器端编程。


'Quick and easy' does not mean that a resulting application will suffer from a maintainability or a performance issue. Netty has been designed carefully with the experiences earned from the implementation of a lot of protocols such as FTP, SMTP, HTTP, and various binary and text-based legacy protocols. As a result, Netty has succeeded to find a way to achieve ease of development, performance, stability, and flexibility without a compromise.

”快速和轻松“并不代表使用了netty的应用会痛苦的面对维护和性能问题。Netty是细心设计的,吸取了很多协议的实现的经验,比如FTP,SMTP,HTTP还有各种2进制和文本的老协议。所以Netty成功地简化了开发性能高,稳定,灵活的应用,并且不会采取任何折中的办法。


Some users might already have found other network application framework that claims to have the same advantage, and you might want to ask what makes Netty so different from them. The answer is the philosophy where it is built on. Netty is designed to give you the most comfortable experience both in terms of the API and the implementation from the day one. It is not something tangible but you will realize that this philosophy will make your life much easier as you read this guide and play with Netty.

一些用户可能发现其他的框架声称他们有同样的优势,所以你会问Netty有什么不同。回答是Netyy的设计哲学的特点不同。Netty的设计是为了提供最舒适的用户体验—Api和从第一天起Netyy本身的实现。这个设计哲学是不可见的,但你一定会发现这样的哲学会让你生活更简单,当你阅读这篇文章和捣弄Netty之后。


Getting Started

开始吧

This chapter tours around the core constructs of Netty with simple examples to let you get started quickly. You will be able to write a client and a server on top of Netty right away when you are at the end of this chapter.

这一章带领你通过简单的例子来了解Netty的核心结构,使得你快速的开始。读完这章,你将能够以Netty为基础,写出客户端和服务器端程序。

If you prefer top-down approach in learning something, you might want to start from Chapter 2, Architectural Overview and get back here.

如果你喜欢从了解Netty本身开始,你可以从第2章(架构概况)开始阅读。


Before Getting Started

开始前准备

The minimum requirements to run the examples which are introduced in this chapter are only two; the latest version of Netty and JDK 1.7 or above. The latest version of Netty is available inthe project download page. To download the right version of JDK, please refer to your preferred JDK vendor's web site.

(很简单,就不细致翻译了),就是需要JDK1.7+ 和下载最新的Netty。

As you read, you might have more questions about the classes introduced in this chapter. Please refer to the API reference whenever you want to know more about them. All class names in this document are linked to the online API reference for your convenience. Also, please don't hesitate to contact the Netty project community and let us know if there's any incorrect information, errors in grammar and typo, and if you have a good idea to improve the documentation.

(很简单,就不细致翻译了),有API文档帮你了解Netty的每一个类。


Writing a Discard Server

写一个哑巴服务器

The most simplistic protocol in the world is not 'Hello, World!' but DISCARD. It's a protocol which discards any received data without any response.

最简单的协议不是“Hello World”,而是哑巴协议。哑巴协议就是服务器无论收到什么数据,都不响应数据给客户端。

To implement the DISCARD protocol, the only thing you need to do is to ignore all received data. Let us start straight from the handler implementation, which handles I/O events generated by Netty.

实现这个协议,仅有一件事忽略所有收到的数据。让我们马上开始实现它的Handler,这个Handler将处理由Netty产生的I/O事件。


package io.netty.example.discard;


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)(2)(3)对应的代码行。

(1)DiscardServerHandler extendsChannelInboundHandlerAdapter, which is an implementation ofChannelInboundHandler.ChannelInboundHandler provides various event handler methods that you can override. For now, it is just enough to extendChannelInboundHandlerAdapter rather than to implement the handler interface by yourself.



(1)代码行,DiscardServerHandler extendsChannelInboundHandlerAdapterChannelInboundHandlerAdapter实现了ChannelInboundHandler.ChannelInboundHandler ,提供几种事件Handler的方法,这些方法你可以override,但目前来说,直接extendChannelInboundHandlerAdapter,不用自己实现ChannelInboundHandler


(2)We override thechannelRead() event handler method here. This method is called with the received message, whenever new data is received from a client. In this example, the type of the received message isByteBuf.

         我们override了channelRead()。每当有客户端消息接收到,这个方法会被调用。这个例子中的消息是ByteBuf。



(3)To implement theDISCARD protocol, the handler has to ignore the received message.ByteBuf is a reference-counted object which has to be released explicitly via therelease() method. Please keep in mind that it is the handler's responsibility to release any reference-counted object passed to the handler. Usually,channelRead() handler method is implemented like the following:


(3)Handler需要忽略收到的信息。不ByteBuf是reference-counted object 所以必须显示的释放,通过release()方法两释放。但一定注意这个Hanlder必须释放所有的传递给它的reference-counted object。一般情况下,Handler的chanelRead()是这样实现的:

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) {

    try {

        // Do something with msg

    } finally {

        ReferenceCountUtil.release(msg);

    }

}


(4)TheexceptionCaught() event handler method is called with a Throwable when an exception was raised by Netty due to an I/O error or by a handler implementation due to the exception thrown while processing events. In most cases, the caught exception should be logged and its associated channel should be closed here, although the implementation of this method can be different depending on what you want to do to deal with an exceptional situation. For example, you might want to send a response message with an error code before closing the connection.

(4)当IO有错误或Handler实现上有问题时,Netty会调用exceptionCaught()方法,并且一个Throwable对象会传入该方法。大多情况下,捕获到的异常需要Log,并且和它相关的Channel需要关闭。当然你的实现可以很独特,这取决于你想如何处理异常。比如你可以返回一个错误编码给客户端,然后再关闭连接。



So far so good. We have implemented the first half of the DISCARD server. What's left now is to write the main() method which starts the server with the DiscardServerHandler.

感觉良好吧。因为我们已经完成了服务器的一般功能了。剩下的是写main()函数,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.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 is a multithreaded event loop that handles I/O operation. Netty provides various EventLoopGroup implementations for different kind of transports. We are implementing a server-side application in this example, and therefore twoNioEventLoopGroup will be used. The first one, often called 'boss', accepts an incoming connection. The second one, often called 'worker', handles the traffic of the accepted connection once the boss accepts the connection and registers the accepted connection to the worker. How many Threads are used and how they are mapped to the createdChannels depends on theEventLoopGroup implementation and may be even configurable via a constructor.


       NioEventLoopGroup是多线程的事件循环,它处理IO操作。Netty提供几种EventLoopGroup的实现是为了不同的数据传输。这个服务器端例子我们使用了两个NioEventLoopGroup,第一个是boss(老板),负责接收连接请求。第二个是worker(工人)负责 数据读写,boss接收连接后会把这个连接注册给worker,worker就能将数据 读取 或写入 至这个连接了。有多少线程和有多少会被chanel使用 取决与 EventLoopGroup的实现 通过 构造函数来配置。



  1.  2ServerBootstrap is a helper class that sets up a server. You can set up the server using aChannel directly. However, please note that this is a tedious process, and you do not need to do that in most cases.
  2.       SeverBootstrap是一个辅助类,帮你搭建服务器。当然你也可以直接使用Channel搭建。但这用是很繁琐的,所大部分情况你不必用Channel来搭建。



  1. Here, we specify to use the NioServerSocketChannel class which is used to instantiate a newChannel to accept incoming connections.

   这一行代码我们指定了 NioServerSocketChannel类来初始化一个新的Channel来接收连接请求。


  1. The handler specified here will always be evaluated by a newly accepted Channel. TheChannelInitializer is a special handler that is purposed to help a user configure a newChannel. It is most likely that you want to configure theChannelPipeline of the newChannel by adding some handlers such asDiscardServerHandler to implement your network application. As the application gets complicated, it is likely that you will add more handlers to the pipeline and extract this anonymous class into a top level class eventually.

这一行代码,我们指定一个HanlderChannelInitializer),而且这个hanlder是会被一个新建的Channel验证的。ChannelInitializer是另一种特殊的Hanlder,是用来帮助你配置一个新的Channel。大多数情况,你需要配置这个新Channel的ChannelPipeLine,只有添加一些Event handler就行,比如我们已经完成的DiscardServerHandler。如果你的运用变得很复杂,你需要想Pipeline添加很多Handler 和 把这个匿名类 抽取出来成为一个独立的类。



  1.   5.You can also set the parameters which are specific to the Channel implementation. We are writing a TCP/IP server, so we are allowed to set the socket options such astcpNoDelay and keepAlive. Please refer to the apidocs of ChannelOption and the specificChannelConfig implementations to get an overview about the supportedChannelOptions.
  2.    你也可以根据Channel的实现来设置一些参数。这个例子是TCP/IP服务,所以我们可以设置socket参数比如tcpNoDelay和keepAlive。通过ChannelOption的api 文档和ChannelConfig的实现你可以大概得知ChannelOptions的参数。


  1. 6. Did you notice option() and childOption()? option() is for the NioServerSocketChannel that accepts incoming connections.childOption() is for the Channels accepted by the parentServerChannel, which isNioServerSocketChannel in this case.
  2. 6.  注意到option()childOption()没有Option是给Boss的NioServerSocketChannel用的,用来接收连接。childOption()是给worker的channel用的。work的channel是被Boss的NioServerSocketChannel认可的。


  1. 7 We are ready to go now. What's left is to bind to the port and to start the server. Here, we bind to the port8080 of all NICs (network interface cards) in the machine. You can now call thebind() method as many times as you want (with different bind addresses.)

7 我们马上就可以启动服务了。剩下的工作是绑定端口,现在我们绑定8080端口。你可以调用bind()无数次,只有端口号每次都不同就行。










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值