Grizzly开发Echo服务器实战
作者:chszs
用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>
服务器端:
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服务器:
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客户端:
java -classpath grizzly-framework.jar EchoClient
已经通过测试,程序运行的非常完美。