1. Netty
Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能、高可靠性的网络服务器和客户端程序。换句话说,Netty是一个NIO框架,使用它可以简单快速地开发网络应用程序,比如客户端和服务端的协议。Netty大大简化了网络程序的开发过程比如TCP和UDP的 Socket的开发。快速和简单”并不意味着应用程序会有难维护和性能低的问题,Netty是一个精心设计的框架,它从许多协议的实现中吸收了很多的经验比如FTP、SMTP、HTTP、许多二进制和基于文本的传统协议,Netty在不降低开发效率、性能、稳定性、灵活性情况下,成功地找到了解决方案。
Netty下载,建议不要下载最新的包。
Netty学习
Netty In Action 中文版
2. 入门--DISCARD(丢弃服务,指的是会忽略所有接收的数据的一种协议)
1). 创建DiscardServerHandler继承自ChannelInboundHandlerAdapter
/**
* 忽略所有消息--继承ChannelHandlerAdapter
* @author mazaiting
*/
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 释放
ReferenceCountUtil.release(msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 打印错误信息
cause.printStackTrace();
// 关闭
ctx.close();
}
}
2). 创建忽略服务器消息的服务器
/**
* 忽略消息的服务器
* @author mazaiting
*/
public class DiscardServer {
/**端口*/
private int port;
public DiscardServer(int port) {
this.port = port;
}
public void run() throws Exception{
// 创建处理I/O操作的多线程事件循环器
// 接收进来的连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 处理已经被接收的连接
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 启动NIO服务的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
// 设置组
.group(bossGroup, workerGroup)
// 设置管道
.channel(NioServerSocketChannel.class)
// 设置过滤
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 设置过滤
ch.pipeline().addLast(new DiscardServerHandler());
}
})
// 后台日志
.option(ChannelOption.SO_BACKLOG, 128)
// 保持存活
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口并开启服务器
ChannelFuture future = bootstrap.bind(port).sync();
// 等待知道这个服务器关闭
future.channel().closeFuture().sync();
} finally {
// 关闭
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8081;
new DiscardServer(port).run();
}
}
3). 测试
在命令提示符窗口,使用telnet localhost 8081
来进行数据的测试, 由于此处为忽略所有的消息,故控制台无打印数据产生。此时修改DiscardServerHandler为
/**
* 忽略所有消息--继承ChannelHandlerAdapter
* @author mazaiting
*/
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 忽略数据
ByteBuf in = (ByteBuf) msg;
try {
System.out.println(in.toString(CharsetUtil.US_ASCII));
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 打印错误信息
cause.printStackTrace();
// 关闭
ctx.close();
}
}
再次使用telnet localhost 8081
测试时,控制台即可打印出数据。
3. ECHO服务(响应式协议)
1). 创建响应式Handler
/**
* 返回客户端发回的消息
* @author mazaiting
*/
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.write(msg);
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 打印错误信息
cause.printStackTrace();
// 关闭
ctx.close();
}
}
2). 创建服务器
/**
* 返回客户端消息的服务器
* @author mazaiting
*/
public class EchoServer {
/**端口*/
private int port;
public EchoServer(int port) {
this.port = port;
}
public void run() throws Exception{
// 创建处理I/O操作的多线程事件循环器
// 接收进来的连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 处理已经被接收的连接
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 启动NIO服务的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
// 设置组
.group(bossGroup, workerGroup)
// 设置管道
.channel(NioServerSocketChannel.class)
// 设置过滤
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 设置过滤
ch.pipeline().addLast(new EchoServerHandler());
}
})
// 后台日志
.option(ChannelOption.SO_BACKLOG, 128)
// 保持存活
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口并开启服务器
ChannelFuture future = bootstrap.bind(port).sync();
// 等待知道这个服务器关闭
future.channel().closeFuture().sync();
} finally {
// 关闭
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8082;
new EchoServer(port).run();
}
}
3). 测试
在命令提示符窗口输入telnet localhost 8081
命令,将' 你好啊'复制进去点击回车
4. TIME服务(时间协议的服务)
1). 创建TimeServerHandler
public class TimeServerHandler extends ChannelInboundHandlerAdapter{
/**
* 将会在连接被建立并且准备进行通信时被调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 申请4个字节
final ByteBuf time = ctx.alloc().buffer(4);
// 存入数据
time.writeInt((int)(System.currentTimeMillis() / 1000L + 2208988800L));
// 写入数据
final ChannelFuture f = ctx.writeAndFlush(time);
// 设置监听
f.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
assert f == future;
ctx.close();
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 打印错误信息
cause.printStackTrace();
// 关闭
ctx.close();
}
}
2). TimeServer
/**
* 返回客户端消息的服务器
* @author mazaiting
*/
public class TimeServer {
/**端口*/
private int port;
public TimeServer(int port) {
this.port = port;
}
public void run() throws Exception{
// 创建处理I/O操作的多线程事件循环器
// 接收进来的连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 处理已经被接收的连接
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 启动NIO服务的辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
// 设置组
.group(bossGroup, workerGroup)
// 设置管道
.channel(NioServerSocketChannel.class)
// 设置过滤
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 设置过滤
ch.pipeline().addLast(new TimeServerHandler());
}
})
// 后台日志
.option(ChannelOption.SO_BACKLOG, 128)
// 保持存活
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 绑定端口并开启服务器
ChannelFuture future = bootstrap.bind(port).sync();
// 等待知道这个服务器关闭
future.channel().closeFuture().sync();
} finally {
// 关闭
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8083;
new TimeServer(port).run();
}
}
3). TimeClientHandler
public class TimeClientHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf mBuf = (ByteBuf) msg;
try {
long currentTimeMillis = (mBuf.readUnsignedInt() - 2208988800L) * 1000L;
System.out.println(new Date(currentTimeMillis));
ctx.close();
} finally {
mBuf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
4). TimeClient
public class TimeClient {
public static void main(String[] args) throws InterruptedException {
String host = "127.0.0.1";
int post = 8083;
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(workerGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
});
// 开启客户端
ChannelFuture future = bootstrap.connect(host, post).sync();
// 等待直到连接关闭
future.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
}