精华内容
下载资源
问答
  • flume1.30userguide中文翻译, flume 中文文档翻译,需要的赶紧下载
  • Geode User Guide 中文翻译版本 GitHub源码地...

    Geode User Guide 中文翻译版本

    GitHub源码地址: https://github.com/wjw465150/GeodeUserGuide

    可阅读的GitPage地址: https://wjw465150.github.io/GeodeUserGuide/

    Apache Geode是一个数据管理平台,可在广泛分布的云架构中提供对数据密集型应用程序的实时,一致的访问。

    Geode跨多个进程汇集内存,CPU,网络资源和可选的本地磁盘,以管理应用程序对象和行为。 它使用动态复制和数据分区技术来实现高可用性,改进的性能,可伸缩性和容错性。 除了作为分布式数据容器之外,Geode还是一个内存数据管理系统,可提供可靠的异步事件通知和有保证的消息传递。

    转载于:https://my.oschina.net/wstone/blog/3018653

    展开全文
  • UG470 - 7 Series FPGAs Configuration User Guide中文翻译版.pdf
  • GEF_User_Guide_中文翻译

    2013-05-14 00:19:26
    GEF_User_Guide_中文翻译
  • Gradle-Plugin-User-Guide-Chinese-Verision, Gradle Plugin User Guide 中文翻译
  • VTK user guide 中文 指导 翻译 2-7章 不是原创,但绝对有用。
  • 但所幸,我在17年底的时候就接触过qnx系统,qnx7.0 中有关于hypervisor 的一些官方文档,以前都是零碎的去看这些文档,所以现在有时间可以好好的去整理一下中文版本,加上自己的理解,这算是一个项目的kick off ...

    由于目前汽车的座舱系统大火,随之而来的基于 poperk/Coldberk 的计算机虚拟化理论的hypervisor大火,但是市面上对于此类书籍的介绍不是很多,汽车方向的座舱域的hypervisor更是比较少.

    但所幸,我在17年底的时候就接触过qnx系统,qnx7.0 中有关于hypervisor 的一些官方文档,以前都是零碎的去看这些文档,所以现在有时间可以好好的去整理一下中文版本,加上自己的理解,这算是一个项目的kick off meeting, 而这个项目目前只有我一个人.

    对于整个的架构,先做一个大致的了解,左边是介绍翻译, 右边是对应的目录名字.

    QNX 虚拟化的环境, 包括他们的架构.                                                                           "QNX Vitual Environments"

    QNX 虚拟化的主机和客户机的镜像, 并且如何将他们转移到对应的目标板子平台中.     "Getting Started"

    开启和关闭hypervisor 以及它的客户机                                                                           "Shutting down the guests and hypervisor"                                                                                                                                            & "Starting and using guests".

    编译 hypervisor 以及它的客户机                                                                                     "Assembling a Hypervisor System and Its                                                                                                                                              Components" 

    配置 hypervisor 主机域(就是hypervisor), 虚拟机, 客户机以及虚拟设备                          "Configuration"

     

    创建以及配置 虚拟机                                                                                                        “Assembling and configuring VMs”

     

    使用hypervisor 以及它的客户机.                                                                                      "Using your hypervisor system"

     

    QNX hypvervisor 的设备以及虚拟设备                                                                             "Devices", "Vitual devices", and                                                                                                                                                          "Physical devices"

    调试你的hypervisor 系统                                                                                                   "Monitoring Troubleshooting, and                                                                                                                                                       Tuning"

     

    杂项和驱动                                                                                                                        "Utilities and Drivers Reference"

     

    这基本阐述了这个用户指导的基本架构.

    For your reference~

    展开全文
  • Netty 4.x User Guide 中文翻译《Netty 4.x 用户指南》pdf版本,值得初级学习netty的好资料
  • Ajax4jsf User Guide 中文翻译翻译专贴: http://bbs.hexiao.cn/read.php?fid=3&tid=13&fpage=1序言Ajax4JSF是一个很容易使用的框架, 在其User Guide中详细介绍了如何使用其功能,找时间学习一下,并翻译出来 以加深...
    Ajax4jsf User Guide 中文翻译
    翻译专贴: http://bbs.hexiao.cn/read.php?fid=3&tid=13&fpage=1

    序言

    Ajax4JSF是一个很容易使用的框架, 在其User Guide中详细介绍了如何使用其功能,找时间学习一下,并翻译出来 以加深理解和方便更多的Java爱好者使用Ajax4jsf 框架.

    翻译进度和问题可以在论坛讨论. http://bbs.hexiao.cn/



    第二章是一个简单的入门程序,看完这一章你就可以建立基本的Ajax程序了.
    Chapter 2. Getting Started with Ajax4jsf


    环境要求
    要使用Ajax4JSF 框架你仅仅需要JDK1.4或者更高,任何JSF实现,和你最喜欢的Servlet容器.在下一章我们将给你提供详细的环境信息.
    Ajax4jsf 被设计为一个容易使用的框架.仅仅有一点简单的设置步骤就可以在你的JSF程序中使用Ajax功能了.


    下载 Ajax4jsf
    最新的Ajax4jsf 发布版在这里

    https://ajax4jsf.dev.java.net/nonav/ajax/ajax-jsf/download.html

    下载.
    安装
    解压 ajax4jsf.zip 文件.
    复制 ajax4jsf.jar and oscache-2.2.jar 到程序的 WEB-INF/lib 文件夹下.
    把下面的内容添加到你的程序的 WEB-INF/web.xml 文件中:
    •  <filter>          <display-name>Ajax4jsf Filter</display-name>          <filter-name>ajax4jsf</filter-name>          <filter-class>org.ajax4jsf.Filter</filter-class>          </filter>          <filter-mapping>          <filter-name>ajax4jsf</filter-name>          <servlet-name>Faces Servlet</servlet-name>          <dispatcher>REQUEST</dispatcher>          <dispatcher>FORWARD</dispatcher>          <dispatcher>INCLUDE</dispatcher>          </filter-mapping>        

      注意. 你可以复制和粘贴上面的内容在 README.txt 文件中.

    • 添加下面的内容:

        <%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>        

      到你每个使用Ajax功能的JSP页面中.

    简单的 AJAX Echo 项目

    让我们来看一个简单的JSF项目. 我们仅仅需要一个JSP页面,里面包含一个Form和一些JSF标签: <h:inputText> 和 <h:outputText>.

    我们这个简单的程序应该可以让我们输入一些文字到<h:inputText>中, 然后发送数据到Server,并在 <h:outputText>中显示Server的响应(给我们一个Echo信息).

    JSP 页面

    下面是一个我们需要的页面代码 (echo.jsp) :

        <%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>    <html>      <head>        <title>repeater </title>       </head>      <body>        <f:view>          <h:form>            <h:inputText size="50" value="#{bean.text}" >               <a4j:support event="onkeyup" reRender="rep"/>            </h:inputText>            <h:outputText value="#{bean.text}" id="rep"/>          </h:form>        </f:view>      </body>    </html>      

    就如你看到的,唯一一行于常给JSF页面代码不同的就是下面的一行

        <a4j:support event="onkeyup" reRender="rep"/>      

    在这里我们在父标签(<h:inputText>)中添加了一个AJAX 支持. 该支持绑定了JavaScript事件“onkeyup” .因此, 每一次该事件发布给父标签时,我们的程序将发送一个AJAX请求到Server.这意味着我们的受管理的bean将包含该“text” 域中我们输入的最新数据.

    <a4j:support> 标签的“reRender” 属性(attribute)定义我们的页面的哪一部分被更新. 在这里,该页面唯一被更新的部位是 <h:outputText> 标签,因为他的ID值和“reRender” 的属性值向匹配. 在一个页面中更新多个元素(elements)也是很简单的:仅仅把他们的IDs放在 “reRender” 属性中就可以了.

    数据 Bean

    当然了,为了运行这个程序我们还需要一个受管理的bean

            package demo;        public class Bean {        private String text;                public Bean() {        }                public String getText() {        return text;        }                public void setText(String text) {        this.text = text;        }        }             

    faces-config.xml

    下一步, 我们需要在faces-config.xml 中注册上面的bean:

        <?xml version="1.0" encoding="UTF-8"?>    <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD 	JavaServer Faces Config 1.1//EN"    "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">    <faces-config>      <managed-bean>        <managed-bean-name>bean</managed-bean-name>        <managed-bean-class>demo.Bean</managed-bean-class>        <managed-bean-scope>request</managed-bean-scope>        <managed-property>          <property-name>text</property-name>          <value/>        </managed-property>      </managed-bean>    </faces-config>      

    注意:这里没有任何东西直接和Ajax4jsf 有关联.

    Web.xml

    最后,不要忘了添加jar文件和更改 web.xml 文件:

        <?xml version="1.0"?>    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">            <display-name>a4jEchoText</display-name>      <context-param>        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>        <param-value>server</param-value>      </context-param>      <filter>        <display-name>Ajax4jsf Filter</display-name>        <filter-name>ajax4jsf</filter-name>        <filter-class>org.ajax4jsf.Filter</filter-class>      </filter>      <filter-mapping>        <filter-name>ajax4jsf</filter-name>        <servlet-name>Faces Servlet</servlet-name>        <dispatcher>REQUEST</dispatcher>        <dispatcher>FORWARD</dispatcher>        <dispatcher>INCLUDE</dispatcher>      </filter-mapping>      <listener>        <listener-class>          com.sun.faces.config.ConfigureListener        </listener-class>      </listener>            <!-- Faces Servlet -->      <servlet>        <servlet-name>Faces Servlet</servlet-name>        <servlet-class>          javax.faces.webapp.FacesServlet        </servlet-class>        <load-on-startup>1</load-on-startup>      </servlet>            <!-- Faces Servlet Mapping -->      <servlet-mapping>        <servlet-name>Faces Servlet</servlet-name>        <url-pattern>*.jsf</url-pattern>      </servlet-mapping>      <login-config>        <auth-method>BASIC</auth-method>      </login-config>    </web-app>      

    就这样了, 现在你的程序应该可以工作了.

    部署

    最终,你可以在Servlet容器中部署你的程序了. 在你喜欢的容器中部署,然后在你的浏览器中输入: http://localhost:8080/a4jEchoText/echo.jsf

     
    展开全文
  • msp430f2系列的资料:结构体系,翻译后的中文文档
  • DW1000用户手册翻译中文版,介绍DW1000工作原理和流程以及各寄存器功能和使用方法,DW1000芯片对802.15协议支持情况
  • Gradle官方文档中文翻译 gradle-user-guide
  • Netty user-guide-for-4.x 中文翻译

    千次阅读 2016-01-18 14:07:25
    原网址:http://netty.io/wiki/user-guide-for-4.x.html 1. Preface  1.1 The Problem  现今我们使用通用应用程序或者类库互相交流。例如,我们经常使用HTTP客户端类库从web服务器抽取...
        原网址:http://netty.io/wiki/user-guide-for-4.x.html
    


    1. Preface
        1.1 The Problem
            现今我们使用通用应用程序或者类库互相交流。例如,我们经常使用HTTP客户端类库从web服务器抽取信息,或者通过web service调用RPC。然而,通用协议和它的实现有时并不能很好衡量。就好像,我们不会用一个通用HTTP服务器来交换大文件,e-mail信息和准实时信息(比如金融信息和多玩家游戏数据)。我们需要的是基于某种目的而经过高度优化的协议实现。例如,你可能想要一种经过优化的HTTP服务器,适用于基于AJAX的聊天应用,流媒体或者大文件传输。你甚至可能想要设计和实现一种精确满足自己需要的全新的协议。另一种不可避免的情况是,你必须处理一个遗留的私有协议,以确保和旧系统的互操作性。上述情况中的要点是,如何在不牺牲最终的应用程序的稳定性和性能的前提下,我们能多快实现那个协议。




    2. The Solution
        Netty项目致力于提供一个异步的、基于事件驱动的网络应用框架,同时提供可维护的、高性能的、可扩展的协议服务器和客户端开发工具。
         换句话说,Netty是一个NIO客户端-服务器框架,能快速、简单地进行网络应用的开发,比如协议服务器/客户端。它极大地简化了网络编程,提高了网络编程的效率,比如TCP和UDP socket服务器。 
        "快速易用"并不意味着所产生的应用会遇到维护性或性能问题。Netty借鉴了许多协议(比如FTP、SMTP、HTTP,以及许多二进制协议和基于文本的传统协议)的实现经验进行了精心设计,因此Netty找到了一种方式来易于开发,同时兼顾性能、稳定性和灵活性。
        一些用户可能已经发现了其他的网络应用框架,它们也声称具有同样的优点,那你可能想问为什么Netty这么与众不同。答案就是它的构建哲学。一开始,Netty就设计能给你最舒服的体验,既包括API,也包括Netty的实现。

     


    3. Getting Started
        本章用简单的例子来展示Netty的核心架构,来让你能快速入门。在你通读本章之后,你马上就能用Netty来写一个客户端和一个服务器。

        3.1 Before Getting Started
            运行本章的例子有两个最低要求:Netty的最新版本和JDK 1.6+。
            在你阅读的时候,你可能会对本章提到的类有很多问题,你可以参考API来了解它们。可以随时联系Netty项目组织。


        3.2 Writing a Discard Server
            世界上最简单的协议不是"Hello, World!",而是DISCARD。DISCARD协议丢弃所有接收到的数据,并且没有响应。
            要实现DISCARD协议,你要做的就是忽略所有接收的数据。先从handler实现开始,handler实现用来处理Netty产生的事件。
    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();
        }
    }

            inbound:入站
                1) DiscardServerHandler继承自ChannelInboundHandlerAdapter,而ChannelInboundHandlerAdapter是ChannelInboundHandler的一个实现。ChannelInboundHandler提供了多种事件处理方法,这些方法都可以被覆盖。目前,继承ChannelInboundHandlerAdapter类已经足够了,不用再自己实现handler接口。
                2) 在此我们覆盖 channelRead() 事件处理方法。当接收到来自客户端的数据时,该方法被调用。本例中,接收到的信息类型是ByteBuf。
                3) 要实现DISCARD协议,handler必须忽略接收的消息。ByteBuf是一种引用计数的对象,必须调用 release() 方法显式释放。注意:handler有责任释放所有传递给该handler的引用计数的对象。通常,channelRead() 方法会像下面这样实现:

    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            // Do something with msg
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
                4) exceptionCaught() 事件处理方法会在以下情况下被调用:因I/O错误导致Netty抛出异常,在处理事件时handler实现抛出异常。大部分情况下,被捕获的异常应该记录下来,并且与之相关的channel应该在这儿关闭,虽然这个方法的实现可以根据你想怎么处理异常情况而不同。例如,你可能想在关闭连接前发送一个带有错误码的响应信息。

            到目前为止,我们已经实现了DISCARD服务器的前半部分。剩下的就是写 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 操作。Netty提供了多种EventLoopGroup实现来处理不同种类的传输。本例中我们正在实现一个服务器端应用,因此将会使用两个 NioEventLoopGroup。第一个NioEventLoopGroup,常常叫做"boss",接受一个 incoming 连接。第二个NioEventLoopGroup,常常叫做"worker",一旦 boss 接受连接并将接受的连接注册到 worker,worker 就可以处理已接受的连接的流量数据。使用多少个线程、线程如何映射到已创建的 Channel,这些都取决于EventLoopGroup实现,甚至可以通过构造器来配置。


                2) ServerBootstrap是一个帮助类,用来设置服务器。你可以直接使用一个 Channel来设置服务器。然而,这是一个繁琐的过程,而且大部分情况下你不需要这么做。
                3) 这里,我们指定使用 NioServerSocketChannel 类实例化一个新的Channel来接受 incoming 连接。
                4) 这里指定的handler总是会被新接受的 Channel 用来求值。ChannelInitializer是一种特殊的handler,用来帮助用户配置一个新的Channel。最可能的是你想配置新的Channel的ChannelPipeline(通过添加一些handler比如DiscardServerHandler)来实现你的网络应用。随着应用变得复杂,你可能会向 pipeline 添加更多的handler,最终,抽取这个匿名类(指本例中的ChannelInitializer)为一个顶层类。
                5) 你也可以针对具体的 Channel 实现来设置参数。我们正在写一个TCP/IP服务器,因此允许我们设置 socket 选项,比如tcpNoDelay和keepAlive。可以参考ChannelOption的 apidoc 和特定的 ChannelConfig 实现来了解关于支持的ChannelOption的概述。
                6) 你注意到 option() 和 childOption() 了吗?option() 用于NioServerSocketChannel接收 incoming 的连接,childOption()用于被父 ServerChannel 接受的 Channel,在本例中就是NioServerSocketChannel。
                7) 剩下的就是要绑定 port,然后启动服务器。这里,我们将机器上的所有NIC(网路界面卡)绑定到8080端口。现在你可以使用不同的绑定地址调用 bind() 方法任意多次。

                8) (我自己加的)bossGroup是parentGroup,workerGroup是childGroup。第 4) 步的 childHandler 是用于workerGroup的,第 5) 步的 option 是用于 bossGroup的,第 6) 步的 childOption 是用于 workerGroup的。
     

            可以启动DiscardServer类,然后使用Socket Tools发送数据进行测试。




        3.3 Looking into the Received Data
            现在我们已经写好了第一个服务器,我们需要测试一下它是否能真正工作。最简单的测试方式是使用telnet命令。例如,可以输入telnet localhost 8080,然后输入一些内容。
            1. 启动netty服务器
            2. 输入telnet ip port,进入telnet命令模式
            3. 输入一些内容




            4. 退出telnet命令,参考http://blog.csdn.net/beyondlpf/article/details/7546120



            也可以在Windows系统上使用Socket Tool来进行测试(推荐)。


            然而,我们能说服务器工作良好吗?我们并不能真正知道,因为这是一个 discard 服务器。你不会得到任何响应。要证明它在工作,我们需要修改服务器,打印一些它接收到的内容。
            我们已经知道,接收到数据的时候,会调用 channelRead() 方法。给DiscardServerHandler的 channelRead() 方法加一些代码:
    @Overridepublic 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)
        }
    }


            这个低效的循环可以被简化为:System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))。
            作为选择,在这儿也可以使用 in.release()。


            discard服务器的全部源码都在 io.netty.example.discard 包。



        3.4 Writing an Echo Server
            到目前为止,我们已经消费了数据,却没有响应。然而,一个服务器应该响应客户端的请求。接下来学习通过实现ECHO协议向客户端发送响应信息,服务器端接收到的数据都会原样返回。
            echo服务器和先前实现的discard服务器唯一的不同是:echo服务器将接收到的数据原样返回,而discard服务器是将接收到的数据打印到控制台。修改 channelRead() 方法:
     public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ctx.write(msg); // (1)
            ctx.flush(); // (2)
        }
                1) ChannelHandlerContext对象提供了多种操作,这些操作能让你触发不同的I/O事件和操作。这里,我们调用 write(Object) 将收到的信息逐字写回。注意,我们没有像在DISCARD例子中那样释放接收到的信息,这是因为Netty会在它被写出的时候释放它。
                2) ctx.write(Object) 没有将信息写出到网络。它被缓存在内部,然后 ctx.flush() 将信息输出到网络。为了简洁,也可以调用ctx.writeAndFlush(msg)。

            echo服务器的全部源码都在 io.netty.example.echo包。
     



        3.5 Writing a Time Server
            这部分要实现的协议是TIME协议。和之前的例子不同,TIME协议发送一个包含32-bit整数的信息而不接收任何请求,并且一旦服务器端发送完信息就立即断开连接。在这个例子中,你会学习如何构造和发送一个信息,并在完成后关闭连接。
            因为我们打算忽略所有接收的数据,并且在连接确定后马上发送一个信息,这次我们不能使用 channelRead() 方法。我们应该覆盖 channelActive() 方法。下面是实现:

    package io.netty.example.time;
    
    public class TimeServerHandler extends ChannelInboundHandlerAdapter {
    
        public void channelActive(final ChannelHandlerContext ctx) { // (1)
                final ByteBuf time = ctx.alloc().buffer(4); // (2)
            time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
    
            final ChannelFuture f = ctx.writeAndFlush(time); // (3)
            f.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) {
                    assert f == future;
                    ctx.close();
                }
            }); // (4)
        }
    
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
                1) 如上面解释过的,当一个连接确立并准备产生流量的时候,channelActive()方法会被调用。我们在这个方法中,写了一个32-bit整数来代表当前时间。
                2) 要发送一个新的信息,我们需要分配一个新的buffer来包含这个信息。我们要写一个32-bit整数,因此需要一个容量至少是4个字节的ByteBuf。通过 ChannelHandlerContext.alloc() 方法来获取当前的 ByteBufAllocator,然后分配一个新的buffer。
                3) 写出构建的信息。
                    但是,flip在哪儿?在NIO中发送信息之前,我们不是常常调用 java.nio.ByteBuffer.flip() 吗?ByteBuf没有这个方法,因为ByteBuf有两个指针:一个用于读操作,另一个用于写操作。当你向ByteBuf写东西时,写索引增加,而读索引不变。读索引和写索引分别代表着信息的起始和结束。
                    相比之下,NIO的buffer在不调用 flip() 方法的情况下,没有提供一种整洁的方式来算出信息内容的起始和结束。当你忘记 flip buffer的时候,会遇到麻烦,因为要么什么都没发送,要么发送了不正确的数据。这样的错误在Netty中不会发生,因为我们有不同的指针用于不同的操作类型。你会发现,随着你越了解Netty,它越会让你的生活更简单,不需要flip。
                    另一点需要注意的地方是,ChannelHandlerContext.write() (and writeAndFlush()) 方法返回了一个ChannelFuture。ChannelFuture代表一个还未发生的I/O操作。它意味着,任何请求操作可能还没有执行因为Netty中所有的操作都是异步的。例如,下面的代码可能会在发送信息前关闭连接:

    Channel ch = ...;
    ch.writeAndFlush(message);
    ch.close();

                    因此,在 ChannelFuture(由write() 方法返回的) 完成之后,你需要调用close()方法,然后它会在写操作完成之后通知它的 listener。注意:close() 也可能不会马上关闭连接,它会返回一个 ChannelFuture。

                4) 那么一个写请求完成之后我们又如何知道?这就像给返回的 ChannelFuture 添加一个 ChannelFutureListener 一样简单。这里,我们创建了一个匿名的 ChannelFutureListener,它会在操作完成之后关闭 Channel。
                    作为另一种选择,你也可以使用预定义的 listener 来简化代码:
    f.addListener(ChannelFutureListener.CLOSE);

            要测试time服务器是否如预期那样工作,可以使用UNIX rdate 命令:
    $ rdate -o <port> -p <host>
    <port>是你在 main() 中指定的端口,<host>通常是localhost。



        3.6 Writing a Time Client
            不像DISCARD和ECHO服务器,需要为TIME协议写一个客户端,因为人不能将32-bit的二进制数据转变为日历上的一个日期。在这部分,我们会讨论如何确保服务器正确工作以及学习如何用Netty写一个客户端。
            Netty中服务器和客户端最大和唯一的区别是:使用了不同的 Bootstrap 和 Channel 实现。看一下下面的代码:
    package io.netty.example.time;
    
    public class TimeClient {
        public static void main(String[] args) throws Exception {
            String host = args[0];
            int port = Integer.parseInt(args[1]);
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                Bootstrap b = new Bootstrap(); // (1)
                b.group(workerGroup); // (2)
                b.channel(NioSocketChannel.class); // (3)
                b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
                b.handler(new ChannelInitializer<SocketChannel>() {
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new TimeClientHandler());
                    }
                });
    
                // Start the client.
                            ChannelFuture f = b.connect(host, port).sync(); // (5)
                            // Wait until the connection is closed.
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
            }
        }
    }
                1) Bootstrap 和 ServerBootstrap很像,Bootstrap 用于非服务器channel,比如客户端或者无连接的channel。
                2) 如果只指定一个EventLoopGroup,它会既用作boss group,又用作worker group。虽然boss worker并不是用于客户端的。
                3) 和NioServerSocketChannel不同,NioSocketChannel用于创建一个客户端Channel。
                4) 注意这里我们没有使用 childOption(),不像我们使用ServerBootstrap时那样,因为客户端 SocketChannel没有parent。
                5) 我们应该调用 connect() 方法而不是 bind() 方法。
            正如你看到的,并不是和服务器端代码完全不同。那 ChannelHandler 的实现呢?这个实现应该从服务器接收一个32-bit整数,将它转换成人类可读的格式,打印转换过的时间,然后关闭连接:

    package io.netty.example.time;
    
    import java.util.Date;
    
    public class TimeClientHandler extends ChannelInboundHandlerAdapter {
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf m = (ByteBuf) msg; // (1)
                   try {
                long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L;
                System.out.println(new Date(currentTimeMillis));
                ctx.close();
            } finally {
                m.release();
            }
        }
    
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
                1) 在TCP/IP中,Netty将来自同级节点(peer)的数据读入到一个ByteBuf。

            TimeClientHandler看起来很简单,和其他服务器端例子(比如TimeServerHandler)也看不出什么区别。然而,这个 handler 有时会拒绝工作并抛出IndexOutOfBoundException。下一部分我们会讨论发生的原因。
            

     


    4. Dealing with a Stream-based Transport
        4.1 One Small Caveat(警告) of Socket Buffer
            在基于流的传输中,比如TCP/IP,接收到的数据存储在一个 socket 接收 buffer 中。不幸的是,基于流进行传输的 buffer 不是一个数据包队列,而是一个字节队列。这也就意味着,即使你发送两个消息作为两个独立的数据包,操作系统不会将它们看作两个消息,而是看成一串字节。因此,并不能保证你读到的确实就是远程同级节点所写的。例如,我们假定操作系统的TCP/IP栈接收到3个数据包:


            由于基于流的协议的一般特性,在你的应用中,有很大几率将上面的3个数据包读成下面那种分散的形式:


            因此,接收部分(翻译为接收端更好理解),不管是服务器端还是客户端,都应该将接收到的数据碎片整理成一个或者多个能很容易被应用逻辑理解、有意义的帧。像上面的例子,接收到的数据应该被整理成下面这样:






        4.2 The First Solution
            让我们回到 TIME 客户端的例子。这里我们有同样的问题。32-bit整数是一个很小量的数据,并不太可能会被经常切分成碎片。然而,问题是它会被切分,并且随着流量增加,切分的可能性也会增加。
            一种过于简单的解决方案是:创建一个内部的累积 buffer,直到这4个字节都被接收到内部 buffer 中。下面是修改过的 TimeClientHandler 实现,解决了那个问题:
    
    
    package io.netty.example.time;
    
    import java.util.Date;
    
    public class TimeClientHandler extends ChannelInboundHandlerAdapter {
        private ByteBuf buf;
    public void handlerAdded(ChannelHandlerContext ctx) {
            buf = ctx.alloc().buffer(4); // (1)
        }
    public void handlerRemoved(ChannelHandlerContext ctx) {
            buf.release(); // (1)
            buf = null;
        }
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf m = (ByteBuf) msg;
            buf.writeBytes(m); // (2)
            m.release();
    
            if (buf.readableBytes() >= 4) { // (3)
                        long currentTimeMillis = (buf.readUnsignedInt() - 2208988800L) * 1000L;
                System.out.println(new Date(currentTimeMillis));
                ctx.close();
            }
        }
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        } 
    } 
                1) ChannelHandler有两个生命期周期 listener 方法:handlerAdded() 和 handlerRemoved()。你可以执行任意的初始化任务,只要这个任务不会阻塞太长时间。
                2) 首先,所有接收到的数据会被累积到 buf。
                3) 然后,handler 必须检查 buf 是否有足够的数据,本例中是4个字节,接着进行实际的业务逻辑。否则,Netty 会在更多数据到达后再次调用 channelRead() 方法,最终会累积到4个字节。



        4.3 The Second Solution
            尽管第一个方案已经解决了 TIME 客户端遇到的问题,修改过的 handler 看起来并不是那么干净。假设有一个更复杂的协议是由多个字段组成,你的 ChannelInboundHandler 实现会很快变得难以维护。
            你可能已经意识到了,一个 ChannelPipeline 上可以添加多个 ChannelHandler,因此,你可以将一个庞大的 ChannelHandler 切分成多个模块来降低应用的复杂度。例如,你可以将 TimeClientHandler 切分成两个 handler:TimeDecoder 处理数据碎片问题和初始的简单版本的 TimeClientHandler。
            幸运的是,Netty提供了一个可扩展的类来帮你马上就能写 TimeDecoder:
    package io.netty.example.time;
    
    public class TimeDecoder extends ByteToMessageDecoder { // (1)
        protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) { // (2)
                if (in.readableBytes() < 4) {
                return; // (3)
            }
    
            out.add(in.readBytes(4)); // (4)
        }
    }
                1) ByteToMessageDecoderChannelInboundHandler的一个实现,能让处理数据碎片问题更简单。
                2) ByteToMessageDecoder在新数据到达时会调用 decode() 方法,它内部维护了一个累积buffer。
                3) decode() 可以决定在累积buffer中没有足够数据的时候不向 out 中添加东西。当接收到更多数据时,ByteToMessageDecoder 将会再次调用 decode()。
                4) 如果 decode() 向 out 添加一个对象,也就意味着 decoder 成功地解码了一条信息。ByteToMessageDecoder会丢弃累积buffer的读取部分。你没有必要解码多条信息。ByteToMessageDecoder会一直调用 decode() 直到无法向 out 中添加东西。

            现在我们向 ChannelPipeline 中插入了另一个 handler,我们应该修改 TimeClient 中 ChannelInitializer 的实现。
    
    
    b.handler(new ChannelInitializer<SocketChannel>() {
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new TimeDecoder(), new TimeClientHandler());
        }
    });
            如果你是一个喜欢冒险的人,你可能会想要试试ReplayingDecoder,它更加简化了 decoder。不过你得查询 API 来获取更多信息。
    public class TimeDecoder extends ReplayingDecoder<Void> {
        protected void decode(
                ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
            out.add(in.readBytes(4));
        } }
            此外,Netty提供了多种开箱即用的decoder,能让你很容易实现大部分协议,并且帮你避免一个巨大的、很难维护的 handler 实现。可以参考下面的包来查看更多详细的例子: 
        io.netty.example.factorial--二进制协议
        io.netty.example.telnet--基于行的文本协议





    5. Speaking in POJO instead of ByteBuf
        上面所有的例子都使用 ByteBuf 作为协议信息的主要数据结构。在这部分,我们使用一个POJO而不是 ByteBuf 来改进TIME协议客户端和服务器的例子。
        在你的ChannelHandler中使用POJO的好处是显而易见的:从 handler 中将从 ByteBuf 中抽取信息的代码分离出来,handler会变得更易维护和重用。在TIME客户端和服务器例子中,我们只读取一个32-bit整数,而这不是直接使用ByteBuf遇到的主要问题。然而,你会发现在你实现一个真实的协议的时候,进行这种分离是必要的。
        首先,让我们定义一个新类型:UnixTime
    package io.netty.example.time;
    
    import java.util.Date;
    
    public class UnixTime {
    
        private final long value;
    
        public UnixTime() {
            this(System.currentTimeMillis() / 1000L + 2208988800L);
        }
    
        public UnixTime(long value) {
            this.value = value;
        }
    
        public long value() {
            return value;
        }
    
        @Overridepublic String toString() {
            return new Date((value() - 2208988800L) * 1000L).toString();
        } } 
        我们现在可以修改 TimeDecoder 来产生一个UnixTime。
     
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        if (in.readableBytes() < 4) {
            return;
        }
    
        out.add(new UnixTime(in.readUnsignedInt())); } 
        用更新过的decoder,TimeClientHandler不再使用 ByteBuf。
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        UnixTime m = (UnixTime) msg;
        System.out.println(m);
        ctx.close(); } 
        同样的技术也可以应用到服务器端。这次首先更新TimeServerHandler:
    public void channelActive(ChannelHandlerContext ctx) {
        ChannelFuture f = ctx.writeAndFlush(new UnixTime());
        f.addListener(ChannelFutureListener.CLOSE); } 
        现在,唯一缺失的是一个encoder,一个ChannelOutboundHandler的实现,负责将一个UnixTime转变成一个ByteBuf。这比写一个decoder更简单,因为编码信息的时候不需要处理数据包碎片和组装。
    package io.netty.example.time;
    
    public class TimeEncoder extends ChannelOutboundHandlerAdapter {
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
            UnixTime m = (UnixTime) msg;
            ByteBuf encoded = ctx.alloc().buffer(4);
            encoded.writeInt((int)m.value());
            ctx.write(encoded, promise); // (1)} 
            1) 在这一行,有不少重要的东西。
                首先,我们按原样传递原始的ChannelPromise,这样当编码过的数据实际写出到网络之后,Netty会将它标记为成功或者失败。
                其次, 我们没有调用ctx.flush()。有一个单独的 handler 方法 void flush(ChannelHandlerContext ctx) 来覆盖 flush()操作。

        为了更加简化, 你可以使用MessageToByteEncoder:
    public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
        protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) {
            out.writeInt((int)msg.value());
        } } 
        遗留的最后一个任务是在服务器端将一个TimeEncoder插入到ChannelPipeline中的TimeServerHandler之前。




    6. Shutting Down Your Application
        关闭一个Netty应用通常就像通过 shutdownGracefully() 关闭 EventLoopGroup 一样简单。它返回一个 Future,当 EventLoopGroup 完全终止并且属于这个组的所有 Channel 都关闭的时候会通知你。





    7. Summary
        在本章,我们快速了解了一下Netty,演示了如何用Netty写一个完全可行的网络应用。
        接下来的章节有更详细的关于Netty的信息。建议了解一下在 io.netty.example 包的Netty的例子。

















    展开全文
  • DW1000用户手册2.10人工翻译中文版,介绍DW1000工作原理和流程以及各寄存器功能和使用方法
  • uC/OS中文翻译

    2018-12-10 14:52:08
    uC/OS相关资料,包括:《µC-OS-III 3.06.01 User's Manual》,《FreeRTOS实时内核使用指南_中文》,《uCOS-III 应用开发指南—基于 STM32F103系列》,《uCOS-III中文翻译》,《嵌入式UCOSII学习》
  • 《创建一个简单的用户界面》 Android应用程序的图形用户界面建立在View(视图)和ViewGroup(试图组)层上。View对象是常见的界面widgets(控件),例如buttons(按钮) ... 或者text fields(输入框)。...
  • 原文资源:《Meltdown- Reading Kernel Memory from User Space》 或者本文文末看原文截图。 目录 Meltdown Abstract 1 Introduction 2 Background 2.1 Out-of-order execution 2.2 Address Spaces 2.3 Cache ...
  • apache-mina-2-user-guide-demos 演示《 Apache MINA 2用户指南》的中文翻译,文中用到的示例源码
  • SIP 中文翻译

    2010-12-22 03:01:17
    1.介绍 extensions.conf中使用sip设备的语法是SIP/devicename,devicename名在下一节中说明。...如果定义了一个SIP代理,可以使用SIP/proxyhostname/user或者SIP/user@proxyhostname形式,prox...
  • 精心翻译的430锁频环时钟模块中文资料,原版资料《MSP430x4xx Family User's Guide》。
  • 这是gradle 2.14版本的官方用户指南对应的中文翻译文档,里面有对gradle全面而详细的介绍。想看对应的英文版的请访问:https://docs.gradle.org/2.14/userguide/userguide.html(国内访问速度很慢,需要自备梯子)。
  • 根据TI官网网站提供的Z-Stack 3.0 Sample Application User’s Guide进行的翻译,学习Zigbee3.0的第一步,翻译质量有点差,希望能帮到英语水平差的同学,也希望高手批评指正!
  • java应用程序的设计英文文献和中文翻译时间:2019-09-08 17:55来源:毕业论文Application Design and Development Practically all use of databases occurs from within application programs. Correspondingly, ...
  • thttpd man 中文翻译

    2008-12-24 22:35:31
    thttpd [-C configfile] [-p port] [-d dir] [-dd data_dir] [-r|-nor] [-s|-nos] [-v|-nov] [-g|-nog] [-u user] [-c cgipat] [-t throttles] [-h host] [-l logfile] [-i pidfile] [-T charset] [-P P3P] [-M max...
  • JUnit 5 User Guide 中文

    2018-01-01 12:25:25
    JUnit 5官方用户指南(http://junit.org/junit5/docs/current/user-guide)的中文翻译(http://sjyuan.cc/junit5/user-guide-cn)
  • gradle plugin user guide中文版,翻译自安卓官网的新构建系统中的gradle插件用户指导一文。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 584
精华内容 233
关键字:

user中文翻译