Grizzly開發Echo服務器實戰

jopen 10年前發布 | 15K 次閱讀 Grizzly 網絡工具包

用 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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!