Grizzly开发Echo服务器实战

jopen 10年前

用 Java编写可伸缩的服务器应用是有难度的,用Java NIO开发、线程管理、为成千上万的用户做服务器扩展,这些都是难点。Grizzly NIO框架的设计目标就是帮助开发者很好地利用Java NIO API,编写出高可扩展性的、功能强大的服务器,并提高了扩展的框架组件:Web Framework(HTTP/S)、WebSocket、Comet等。

Grizzly 2.3开发Echo服务器/客户端的例子

1、下载grizzly-framework.jar库

Maven依赖

 
<dependency>        <groupId>org.glassfish.grizzly</groupId>        <artifactId>grizzly-framework</artifactId>        <version>2.3.16</version>    </dependency>

或下载地址: http://central.maven.org/maven2/org/glassfish/grizzly/grizzly-framework/2.3.16/grizzly-framework-2.3.16.jar
2014.10.23日刚发布了2.3.17版,地址见: 
https://maven.java.net/content/repositories/releases/org/glassfish/grizzly/grizzly-framework/2.3.17/grizzly-framework-2.3.17.jar
也可以用这个版本。

服务器端:

1)创建Echo过滤器

Echo过滤器负责把接收到的消息(不管其类型)原样返回给Grizzly连接。
    import java.io.IOException;                import org.glassfish.grizzly.filterchain.BaseFilter;        import org.glassfish.grizzly.filterchain.FilterChainContext;        import org.glassfish.grizzly.filterchain.NextAction;                        public class EchoFilter extends BaseFilter{                        /**            * 仅处理读操作,当消息到来时进行处理            * @param ctx  处理的上下文            * @return 下一个动作            */            @Override            public NextAction handleRead(FilterChainContext ctx) throws IOException{                // Peer address用于无连接的UDP连接                final Object peerAddress = ctx.getAddress();                final Object message = ctx.getMessage();                System.out.println("Server received: " + message);                ctx.write(peerAddress, message, null);                return ctx.getStopAction();            }        }  

2)服务器初始化代码
所有的服务器过滤器链都准备好,开始初始化并启动服务器。
    import java.io.IOException;        import java.nio.charset.Charset;        import java.util.logging.Logger;                        import org.glassfish.grizzly.filterchain.FilterChainBuilder;        import org.glassfish.grizzly.filterchain.TransportFilter;        import org.glassfish.grizzly.nio.transport.TCPNIOTransport;        import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;        import org.glassfish.grizzly.utils.StringFilter;                        public class EchoServer {            private static final Logger logger = Logger.getLogger(EchoServer.class.getName());            public static final String HOST = "localhost";            public static final int PORT = 7777;                        public static void main(String[] args) throws IOException{                // 用FilterChainBuilder创建过滤器链                FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless();                                // 添加TransportFilter,它负责从连接中读数据,并写数据到连接                filterChainBuilder.add(new TransportFilter());                // 字符串过滤器StringFilter负责缓冲和字符串之间的转换                filterChainBuilder.add(new StringFilter(Charset.forName("UTF-8")));                // 过滤器EchoFilter负责把接收到的消息原样返回给连接                filterChainBuilder.add(new EchoFilter());                                // 创建TCP传输                final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();                transport.setProcessor(filterChainBuilder.build());                try{                    // 绑定传输,开始对主机+端口进行监听                    transport.bind(HOST, PORT);                    // 开始传输                    transport.start();                                        logger.info("Press any key to stop the Echo server...");                    System.in.read();                } finally{                    logger.info("Stopping transport...");                    // 停止传输服务器                    transport.shutdown();                                        logger.info("Stopped transport...");                }            }        }  

运行Echo服务器:
  1. java -classpath grizzly-framework.jar EchoServer  

客户端:

1)创建客户端过滤器

客户端过滤器负责重定向服务器的响应到标准输出。要注意,客户端过滤器需要FilterChainContext消息
    import java.io.IOException;                        import org.glassfish.grizzly.filterchain.BaseFilter;        import org.glassfish.grizzly.filterchain.FilterChainContext;        import org.glassfish.grizzly.filterchain.NextAction;                        public class ClientFilter extends BaseFilter{                        /**            * 仅处理读操作,当消息到来时进行处理            * @param ctx  处理的上下文            * @return 下一个动作            */            @Override            public NextAction handleRead(final FilterChainContext ctx) throws IOException{                // 从上下文得到字符串消息,过滤器链只使用了字符串过滤器StringFilter                final String serverResponse = ctx.getMessage();                System.out.println("Server echo: " + serverResponse);                return ctx.getStopAction();            }        }  

2)客户端代码
简单的客户端,向Echo服务器发送消息并等待响应。
    import java.io.BufferedReader;        import java.io.IOException;        import java.io.InputStreamReader;        import java.nio.charset.Charset;        import java.util.concurrent.ExecutionException;        import java.util.concurrent.Future;        import java.util.concurrent.TimeUnit;        import java.util.concurrent.TimeoutException;        import java.util.logging.Logger;                        import org.glassfish.grizzly.Connection;        import org.glassfish.grizzly.Grizzly;        import org.glassfish.grizzly.filterchain.FilterChainBuilder;        import org.glassfish.grizzly.filterchain.TransportFilter;        import org.glassfish.grizzly.nio.transport.TCPNIOTransport;        import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;        import org.glassfish.grizzly.utils.StringFilter;                        import ch.echo.server.EchoServer;                        public class EchoClient {            private static final Logger logger = Grizzly.logger(EchoClient.class);                        public static void main(String[] args) throws IOException,                ExecutionException, InterruptedException, TimeoutException{                Connection connection = null;                                // 用FilterChainBuilder类创建过滤器链                FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless();                // 添加传输过滤器,它负责从连接读数据并向连接写数据                filterChainBuilder.add(new TransportFilter());                // 添加字符串过滤器,它负责缓冲和字符串之间的转换                filterChainBuilder.add(new StringFilter(Charset.forName("UTF-8")));                // 添加客户端过滤器,他负责把服务器响应重定向到标准输出                filterChainBuilder.add(new ClientFilter());                                // 创建TCP传输                final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();                transport.setProcessor(filterChainBuilder.build());                                try{                    // 启动传输                    transport.start();                                        // 异步执行,连接到服务器                    Future<Connection> future = transport.connect(EchoServer.HOST, EchoServer.PORT);                    // 等待连接操作的完成                    connection = future.get(10, TimeUnit.SECONDS);                                        assert connection!=null;                    System.out.println("Ready...(\"q\" to exit");                    final BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));                    do{                        final String userInput = inReader.readLine();                        if(userInput==null || "q".equals(userInput))                            break;                                                connection.write(userInput);                    } while(true);                } finally{                    // 关闭客户端连接                    if(connection!=null)                        connection.close();                                        // 停止传输                    transport.shutdownNow();                }            }        }  

运行Echo客户端:
  1. java -classpath grizzly-framework.jar EchoClient  

已经通过测试,程序运行的非常完美。

作者:chszs,转载需注明。博客主页:http://blog.csdn.net/chszs