代码
服务端
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("服务器准备好了");
ChannelFuture cf = serverBootstrap.bind(6668).sync();
cf.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress()+":连接成功");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf result = (ByteBuf) msg;
byte[] bytesMsg = new byte[result.readableBytes()];
result.readBytes(bytesMsg);
String resultStr = new String(bytesMsg);
System.out.println("数据为:"+resultStr);
result.release();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端",CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端
public class NettyClient {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup loopGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(loopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
ChannelFuture cf = bootstrap.connect("127.0.0.1", 6668).sync();
cf.channel().closeFuture().sync();
}finally {
loopGroup.shutdownGracefully();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("hello,server", CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf bf = (ByteBuf) msg;
System.out.println(bf.toString(CharsetUtil.UTF_8));
}
}
NioEventLoopGroup
子线程数是多少:追到最下边可以看到默认值为
NettyRuntime.availableProcessors() * 2
是你电脑CPU核数乘2,以我电脑为例是8.
平时因为boosGroup因为只处理连接,所以子线程数量可以较少,worker子线程则较多。
以8个子线程为例,当有一个客户端,则分配给第一个(虽然无序,但是可以这么理解)线程,以此类推,如果出现第九个客户端,则交给第一个线程处理。
一个线程包含的信息
在pipline中有长时间任务时,我们让任务异步执行,会把任务放入taskQueue,以服务端读数据为例
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000*10);
System.out.println("休眠十秒");
}catch (Exception e){
e.printStackTrace();
}
}
});
ByteBuf result = (ByteBuf) msg;
byte[] bytesMsg = new byte[result.readableBytes()];
result.readBytes(bytesMsg);
String resultStr = new String(bytesMsg);
System.out.println("数据为:"+resultStr);
result.release();
}
我们可以看到,已经放入taskQueue
因为是同一个线程,如果再放入一个睡眠20s的任务,那么两个task一种执行30s。
定时任务,同上,会把任务放在scheduledTaskQueue。
ctx.channel().eventLoop().schedule(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000*10);
System.out.println("休眠十秒");
}catch (Exception e){
e.printStackTrace();
}
}
},5, TimeUnit.SECONDS);
channel和pipline
ChannelHandlerContext是上下文,几乎所有的信息都可以找他获取。
channel和pipline属于你中有我,我中有你
从head和tail也可以看出来pipline其实是个链表
异步