zoukankan      html  css  js  c++  java
  • Writing a Discard Server 写个抛弃服务器 世上最简单的协议

    Netty.docs: User guide for 4.x https://netty.io/wiki/user-guide-for-4.x.html

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

    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.

    世上最简单的协议不是'Hello, World!' 而是 DISCARD(抛弃服务)。这个协议将会抛弃任何收到的数据,而不响应。

    为了实现 DISCARD 协议,你只需忽略所有收到的数据。让我们从 handler (处理器)的实现开始,handler 是由 Netty 生成用来处理 I/O 事件的。

     

    Writing a Discard Server 写个抛弃服务器 · GitBook https://waylau.com/netty-4-user-guide/Getting%20Started/Writing%20a%20Discard%20Server.html

    <?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>nettyG</groupId>
    <artifactId>nettyA</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
    <dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.30.Final</version>
    </dependency>
    </dependencies>
    </project>


    D: ettyAsrcmainjavacom estDiscardServerHandler.java

    package com.test;

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

    public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
    ((ByteBuf) msg).release();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
    }
    }


    1.DiscardServerHandler 继承自 ChannelInboundHandlerAdapter,这个类实现了 ChannelInboundHandler接口,ChannelInboundHandler 提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承 ChannelInboundHandlerAdapter 类而不是你自己去实现接口方法。

    2.这里我们覆盖了 chanelRead() 事件处理方法。每当从客户端收到新的数据时,这个方法会在收到消息时被调用,这个例子中,收到的消息的类型是 ByteBuf

    3.为了实现 DISCARD 协议,处理器不得不忽略所有接受到的消息。ByteBuf 是一个引用计数对象,这个对象必须显示地调用 release() 方法来释放。请记住处理器的职责是释放所有传递到处理器的引用计数对象。通常,channelRead() 方法的实现就像下面的这段代码:

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

    4.exceptionCaught() 事件处理方法是当出现 Throwable 对象才会被调用,即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的 channel 给关闭掉。然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。

    目前为止一切都还不错,我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。

     

    1. DiscardServerHandler extends ChannelInboundHandlerAdapter, which is an implementation of ChannelInboundHandlerChannelInboundHandler provides various event handler methods that you can override. For now, it is just enough to extend ChannelInboundHandlerAdapter rather than to implement the handler interface by yourself.
    2. We override the channelRead() 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 is ByteBuf.
    3. To implement the DISCARD protocol, the handler has to ignore the received message. ByteBuf is a reference-counted object which has to be released explicitly via the release() 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:
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            // Do something with msg
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
    1. The exceptionCaught() 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.

    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.

    D:
    ettyAsrcmainjavacom	estDiscardServer.java
    package com.test;

    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;

    public class DiscardServer {
    private int port;

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

    public void run() throws Exception {
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel ch) throws Exception {
    ch.pipeline().addLast(new DiscardServerHandler());
    }
    }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);

    ChannelFuture f = b.bind(port).sync();

    //等待服务器,socket关闭。在这个例子中,这不会发生,但你可以优雅第关闭你的服务器。

    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();
    }
    }

    https://waylau.gitbooks.io/netty-4-user-guide/Getting%20Started/Looking%20into%20the%20Received%20Data.html

    Looking into the Received Data

    Now that we have written our first server, we need to test if it really works. The easiest way to test it is to use the telnet command. For example, you could enter telnet localhost 8080 in the command line and type something.

    However, can we say that the server is working fine? We cannot really know that because it is a discard server. You will not get any response at all. To prove it is really working, let us modify the server to print what it has received.

    We already know that channelRead() method is invoked whenever data is received. Let us put some code into the channelRead()method of the DiscardServerHandler:

    @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. This inefficient loop can actually be simplified to: System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))
    2. Alternatively, you could do in.release() here.

    If you run the telnet command again, you will see the server prints what has received.

    The full source code of the discard server is located in the io.netty.example.discard package of the distribution.

    现在我们已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命令。例如,你可以在命令行上输入telnet localhost 8080或者其他类型参数。

    +

    然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。

    我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 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.这个低效的循环事实上可以简化为:System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))

    2.或者,你可以在这里调用 in.release()。

    如果你再次运行 telnet 命令,你将会看到服务端打印出了他所接收到的消息。

     

    package com.test;

    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.util.CharsetUtil;
    import io.netty.util.ReferenceCountUtil;

    public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
    // ((ByteBuf) msg).release();
    ByteBuf in = (ByteBuf) msg;
    try {
    while (in.isReadable()) { // (1)这个低效的循环事实上可以简化为:
    //System.out.println(in.toString(CharsetUtil.US_ASCII));
    System.out.print((char) in.readByte());
    System.out.flush();
    }
    } finally {
    ReferenceCountUtil.release(msg);// (2)
    }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
    cause.printStackTrace();
    ctx.close();
    }
    }

    "C:Program FilesJavajdk1.8.0_171injava" "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2017.3.4libidea_rt.jar=60542:C:Program FilesJetBrainsIntelliJ IDEA 2017.3.4in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_171jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_171jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_171jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_171jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_171jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_171jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_171jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_171jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_171jrelibext ashorn.jar;C:Program FilesJavajdk1.8.0_171jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_171jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_171jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_171jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_171jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_171jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_171jrelibjce.jar;C:Program FilesJavajdk1.8.0_171jrelibjfr.jar;C:Program FilesJavajdk1.8.0_171jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_171jrelibjsse.jar;C:Program FilesJavajdk1.8.0_171jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_171jrelibplugin.jar;C:Program FilesJavajdk1.8.0_171jrelib esources.jar;C:Program FilesJavajdk1.8.0_171jrelib t.jar;D:javaNettyActionNettyA argetclasses;C:Userssas.m2 epositoryio etty etty-all4.1.30.Final etty-all-4.1.30.Final.jar" com.test.DiscardServer
    GET / HTTP/1.1
    Host: localhost:8080
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6,cy;q=0.5
    Cookie: Pycharm-8d0b2786=568b4aae-c829-4e47-ab4b-ddc1476c8726; Idea-80a56cc9=5ec4599e-2cf3-4fc1-b0c2-3fb43cf0485d





     

     









  • 相关阅读:
    Arch安装KDE5
    Gentoo解决Windows系统txt文本中文乱码问题
    用e2fsck修复受损的linux文件系统
    linux远程控制windows
    vim常用命令
    bash shell 常用快捷键
    Deepin Linux 安装JDK
    Linux清除磁盘上的RAID信息
    IDEA社区版运行并发布web项目
    CentOS 7 ibus 导入第三方词库
  • 原文地址:https://www.cnblogs.com/rsapaper/p/9936691.html
Copyright © 2011-2022 走看看