欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Practical Netty (1) 基于Netty实现的一个rdate server实例  

程序员文章站 2022-05-10 10:22:01
...

Practical Netty (1) 基于Netty实现的一个rdate server实例


Netty 是一个高效的 Java 网络框架,简单的介绍可参见《Java NIO框架Mina、Netty、Grizzly介绍与对比》一文。对于不熟悉 NIO 的 Java 开发者,Netty 的使用需要一小段的时间来熟悉。当然 Netty 已经更好地封装了 NIO,所以您大可不必先去了解完 NIO,再来了解 Netty。

下面是一个简单的 rdate server 实例,大部分代码参考 Netty Official Examples。什么是 rdate?如果你是 *nix 用户的话,就一定知道:

rdate is a command to set the system's date from a remote host.

具体如下:

rdate displays and sets the local date and time from the host name or
address given as the argument.  The time source may be an RFC 868 TCP
protocol server, which is usually implemented as a built-in service of
inetd(8), or an RFC 2030 protocol SNTP/NTP server.  By default, rdate
uses the RFC 868 TCP protocol.

RdateServer.java

package com.sinosuperman.test.netty;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

public class RdateServer {
    private static int port = 28080;

    public static void main(String[] args) {

        // ChannelFactory is a factory which creates and manages Channels and
        // its related resources. 
        ChannelFactory factory =
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),  // boss executor
                        Executors.newCachedThreadPool()); // worker executor

        // ServerBootstrap is a helper class that sets up a server. You can set
        // up the server using a Channel directly. However, please note that
        // this is a tedious process and you do not need to do that in most
        // cases.
        ServerBootstrap bootstrap = new ServerBootstrap(factory);

        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() throws Exception {
                return Channels.pipeline(new RdateServerHandler());
            }
        });

        bootstrap.setOption("child.tcpNoDelay", true);
        bootstrap.setOption("child.keepAlive", true);

        bootstrap.bind(new InetSocketAddress(port));
    }
}

RdateServerHandler.java

下面比较有意思的就是和 NIO 中的 ByteBuffer 类似的 ChannelBuffer,很好用。ChannelFuture 也是 Netty 中经常使用到的。

package com.sinosuperman.test.netty;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

public class RdateServerHandler extends SimpleChannelHandler {
    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
            throws Exception {
        Channel ch = e.getChannel();

        // To send a new message, we need to allocate a new buffer which will
        // contain the message. We are going to write a 32-bit integer, and
        // therefore we need a ChannelBuffer whose capacity is 4 bytes. The
        // ChannelBuffers helper class is used to allocate a new buffer. Besides
        // the buffer method, ChannelBuffers provides a lot of useful methods
        // related to the ChannelBuffer. For more information, please refer to
        // the API reference.
        ChannelBuffer time = ChannelBuffers.buffer(4);
        time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));

        ChannelFuture f = ch.write(time);

        f.addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
            throws Exception {
        e.getCause().printStackTrace();
        Channel ch = e.getChannel();
        ch.close();
    }
}

这里比较重要的是时间的计算公式:

System.currentTimeMillis() / 1000L + 2208988800L

具体不细说了,算是一个小常识吧。

客户端测试

客户端就是 Linux 提供的 rdate 命令,如下方式测试:

$ rdate -o <rdate_server_port> -p <rdate_server_ip>

这里默认使用的是 28080。

$rdate -o 28080 -p 127.0.0.1
Fri Dec 28 14:21:05 CST 2012

-

转载请注明来自钟超(Poechant)的 CSDN 博客:http://blog.csdn.net/poechant,作者微博:http://weibo.com/lauginhom

-