Netty入门目录
- Netty开发环境
- 服务端程序Demo
- 客户端程序Demo
- 运行结果
Netty环境搭建
搭建maven项目引入相关jar,目前最新的jar为netty-all-5.0.0.Alpha2.jar。
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
Netty服务端Demo
废话不多少,直接上代码
package com.example.netty.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @version 1.0
* @Desription:
* @Author:Hui
* @CreateDate:2018/6/16 21:03
*/
public class TimeServer {
public static void main(String[] args) {
int port = 8080;
if(args != null && args.length > 0){
port = Integer.valueOf(args[0]);
}
try {
new TimeServer().bind(port);
} catch (Exception e) {
e.printStackTrace();
}
}
public void bind(int port) throws Exception {
//配置服务端NIO线程组,这里创建了2个NioEventLoopGrou,
// 专门用于网络事件处理。一个用于服务端接受客户端连接,一个进行SocketChannel的网络读写
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//new ServerBootsrap()是Netty用于启动NIO服务端的辅助启动类。
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup,workerGroup)
//此处相当于设置创建Channel为NIOServerSocketChannel,它的功能对应JDK NIO中的ServerSocketChannel。
.channel(NioServerSocketChannel.class)
//
.option(ChannelOption.SO_BACKLOG,1024)
// 绑定I/O事件的处理类,它的作用是用于网络I/O读写
.childHandler(new ChildChannelHandler());
//绑定监听端口,随后调用它的同步阻塞方法sync等待绑定操作完成。成功后返回一个ChannelFuture,主要用于异步操作的通知回调
ChannelFuture future = b.bind(port).sync();
//此处进行方法阻塞,等待服务端链路关闭后,main函数才推出
future.channel().closeFuture().sync();
} finally {
// shutdownGracefully()方法释放跟shutdownGracefull相关联的资源。优雅退出
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeServerHandler());
}
}
}
package com.example.netty.server;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import java.util.Date;
/**
* @version 1.0
* @Desription: 继承ChannelHandlerAdpater,用于网络事件进行读写操作,通常我们只需要关注channelRead和exceptionCaught方法
* @Author:Hui
* @CreateDate:2018/6/16 21:11
*/
public class TimeServerHandler extends ChannelHandlerAdapter {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//当发生异常时,关闭ChannelHandlerContext,释放和ChannelHandlerContext相关的句柄等资源
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//类型转换为Netty的ByteBuf对象,相当于NIO的ByteBuffer。
ByteBuf buf = (ByteBuf) msg;
//buf.readableBytes()方法获取了缓冲区可读的字节数,可根据字节数创建byte数组
byte[] req = new byte[buf.readableBytes()];
//readBytes方法将缓冲区的字节数复制到新建的数组中
buf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("The Time Server receive order : " + body );
String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//此方法将消息返送到SocketChannel中发送给对方。
ctx.flush();
}
}
Netty客户端Demo
package com.example.netty.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @version 1.0
* @Desription:
* @Author:Hui
* @CreateDate:2018/6/16 21:22
*/
public class TimeClient01 {
public static void main(String[] args) {
int port = 8080;
if(args != null && args.length > 0 ){
port = Integer.valueOf(args[0]);
}
try {
new TimeClient01().connect(port,"127.0.0.1");
} catch (Exception e) {
e.printStackTrace();
}
}
private void connect(int port, String host) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
ChannelFuture f = b.connect(host,port).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
package com.example.netty.client;
import com.example.nio.client.TimeClientHandle;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerInvoker;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @version 1.0
* @Desription:
* @Author:Hui
* @CreateDate:2018/6/16 21:28
*/
public class TimeClientHandler extends ChannelHandlerAdapter {
private static final Logger logger = LoggerFactory.getLogger(TimeClientHandle.class);
private final ByteBuf firstMessage;
public TimeClientHandler() {
byte[] req = "QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.warn("Unexpected exception from downstream : " + cause.getMessage());
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("Now is "+ body);
// ctx.close();
}
}
运行调试
服务端结果:
23:04:58.777 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
23:04:58.777 [main] DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 8
23:04:58.808 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
23:04:58.808 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
23:04:58.980 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 98:ee:cb:67:ea:36:00:00 (auto-detected)
23:04:58.996 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 1124 (auto-detected)
23:04:58.996 [main] DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0xc4537a7c14e729e1
23:04:59.011 [main] DEBUG io.netty.channel.ChannelOutboundBuffer - -Dio.netty.threadLocalDirectBufferSize: 65536
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - Platform: Windows
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - Java version: 8
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noUnsafe: false
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.ByteBuffer.cleaner: available
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: true
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noJavassist: false
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - Javassist: unavailable
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes. Please check the configuration for better performance.
23:04:59.027 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
23:04:59.058 [main] DEBUG io.netty.util.NetUtil - Loopback interface: Software Loopback Interface 1
23:04:59.058 [main] DEBUG io.netty.util.NetUtil - Loopback address: /127.0.0.1 (primary)
23:04:59.058 [main] DEBUG io.netty.util.NetUtil - Loopback address: /0:0:0:0:0:0:0:1
客户端结果:
23:07:04.308 [main] DEBUG io.netty.util.internal.logging.InternalLoggerFactory - Using SLF4J as the default logging framework
23:07:04.308 [main] DEBUG io.netty.channel.MultithreadEventLoopGroup - -Dio.netty.eventLoopThreads: 8
23:07:04.340 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
23:07:04.340 [main] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
23:07:04.511 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 98:ee:cb:67:ea:36:00:00 (auto-detected)
23:07:04.527 [main] DEBUG io.netty.channel.DefaultChannelId - -Dio.netty.processId: 3736 (auto-detected)
23:07:04.527 [main] DEBUG io.netty.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0xbaf957b74d4b8d21
23:07:04.543 [main] DEBUG io.netty.channel.ChannelOutboundBuffer - -Dio.netty.threadLocalDirectBufferSize: 65536
23:07:04.558 [main] DEBUG io.netty.util.internal.PlatformDependent - Platform: Windows
23:07:04.558 [main] DEBUG io.netty.util.internal.PlatformDependent - Java version: 8
23:07:04.558 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noUnsafe: false
23:07:04.558 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.ByteBuffer.cleaner: available
23:07:04.558 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Buffer.address: available
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.theUnsafe: available
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent0 - sun.misc.Unsafe.copyMemory: available
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent0 - java.nio.Bits.unaligned: true
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent - sun.misc.Unsafe: available
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noJavassist: false
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent - Javassist: unavailable
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent - You don't have Javassist in your class path or you don't have enough permission to load dynamically generated classes. Please check the configuration for better performance.
23:07:04.574 [main] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
23:07:04.590 [nioEventLoopGroup-2-1] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetectionLevel: simple
Now is Sat Jun 16 23:07:04 CST 2018
此时服务端新增日志:
23:07:04.605 [nioEventLoopGroup-3-1] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetectionLevel: simple
The Time Server receive order : QUERY TIME ORDER
运行结果正确。**注意:**此时client不会主动关闭,只要链路不断,client就不关闭。
总结
这里对Netty代码作了一个简单的了解,如果有兴趣,可跟下来深入解读。