Netty的作用
Netty是一个异步事件驱动的网络应用程序框架,可以在其基础上开发高性能的面向协议的服务器和客户端。其支持OIO,NIO,EPOLL模型。
知识准备
IO和NIO的区别
Java Socket
网络NIO通道的使用
选择器Selector
Reactor模型
Reactor模型是在NI0模型的基础上拓展的。
NIO模型,特点就是两个线程,一个线程无阻塞接收,注册读写对应的通道,另一个线程阻塞的执行不同key对应的通道。
Reactor模型:Reactor+Handler
Reactor负责派发响应事件给Handler。
Handler负责绑定事件,事件处理,写回Channel通道。
入门程序
服务器SpyServer
public class SpyServer {
private int port;
public SpyServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup elg = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(elg)
.channel(NioServerSocketChannel.class)
.localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new SpyServerHandler());
}
});
ChannelFuture cf = b.bind().sync();
cf.channel().closeFuture().sync();
elg.shutdownGracefully().sync();
}
public static void main(String[] args) throws Exception {
new SpyServer(8080).start();
}
}
服务器事件处理器SpyServerHandler
class SpyServerHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
byte[] req = new byte[in.readableBytes()];
in.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("服务器接收到客户端请求:" + body);
String currentTime="";
if ("查询时间请求".equals(body)) {
currentTime = new Date(System.currentTimeMillis()).toString();
}
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
客户端SpyClient
public class SpyClient {
public void connect(int port, String host) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
sc.pipeline().addLast(new SpyClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
group.shutdownGracefully().sync();
}
public static void main(String[] args) throws Exception {
new SpyClient().connect(8080, "127.0.0.1");
}
}
客户端事件处理器SpyClientHandler
class SpyClientHandler extends ChannelInboundHandlerAdapter {
private ByteBuf firstMessage;
public SpyClientHandler() {
byte[] req = "QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
// 当被通知Channel是活跃的时候,发送一条消息
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("查询时间请求", CharsetUtil.UTF_8));
}
// 记录已接收消息的转存
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
System.out.println("客户端接收到请求:" + in.toString(CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
结果:
服务器接收到客户端请求:查询时间请求
客户端接收到请求:2020-05-31
网友评论