Netty 学习笔记
- 简单netty 模型
- BoosGroup 线程维护selector ,只关注accpector,当接受到accept事件,获取到对应的socketChannel并注册到worker线程循环,并进行维护。
- 当worker线程中监听到自己感兴趣的事件后 , 就进行处理, 注意handler已经加入到通道。
代码样例
server 端
package src.com.nettys;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* netty server
*/
public class NettyServer {
public static void main(String[] args) {
// 创建BoosGroup 和 workGroup
// 创建两个线程组 boosGroup 和 workGroup
// boosGroup 和 workerGroup含有的 子线程NioEventGroup 的个数
EventLoopGroup boosGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup();
try{
// 创建服务器的启动对象
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boosGroup , workGroup)
.channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel 作为连接通道
.option(ChannelOption.SO_BACKLOG , 128) // 设置线程队列得到的连接个数
.childOption(ChannelOption.SO_KEEPALIVE , true)
.childHandler(new ChannelInitializer<SocketChannel>() { // 创建一个初始化对象
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
System.out.println("客户 socketChannel is hashCode: " + socketChannel.hashCode());
socketChannel.pipeline().addLast(new NettyHandlerServer());
}
});
System.out.println(" 服务器is readly ...... ");
// 绑定一个端口, 并启动一个监听服务
ChannelFuture channelFuture = bootstrap.bind(6668).sync();
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (channelFuture.isSuccess()) {
System.out.println("绑定端口号成功 !");
} else {
System.out.println("绑定端口号失败 !");
}
}
});
// 对关闭的通道进行监听
channelFuture.channel().closeFuture().sync();
}catch (Exception e) {
e.printStackTrace();
} finally {
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
server handler
package src.com.nettys;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;
import java.nio.ByteBuffer;
public class NettyHandlerServer extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(" 服务器读取线程: " + Thread.currentThread().getName() + " channel= " + ctx.channel());
System.out.println(" server ctx " + ctx);
System.out.println( " 查看channel 和 pipine 的关系");
Channel channel = ctx.channel();
ChannelPipeline pipeline = channel.pipeline(); // 本质是一个双向链接 , 出栈入栈
// 将msg 转换成一个 butBuf
ByteBuf byteBuf = (ByteBuf) msg;
System.out.println("客户端发送的消息是: " + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("发送消息的客户端地址: " + channel.localAddress());
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 将数据写如到缓存,并刷星
// 一般讲, 我们对这个数据进行编码
ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端~(>^ω^<)喵1", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客户端样例
package src.com.nettys;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class NettyClient {
public static void main(String[] args) {
// 客户端需要一个事件循环组
EventLoopGroup loopGroup = new NioEventLoopGroup();
try{
// 创建客户端启动对象
// 使用bootStrap
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(loopGroup) // 设置线程组
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端启动ok .....");
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync();
// 给关闭通道进行监听
channelFuture.channel().closeFuture().sync();
}catch (Exception e) {
e.printStackTrace();
} finally {
loopGroup.shutdownGracefully();
}
}
}
clientHandler
package src.com.nettys;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.EventExecutorGroup;
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 读取客户端推送的消息
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf)msg;
System.out.println(" 服务器回复消息: " + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("服务器的地址: " + ctx.channel().localAddress());
}
/**
* 推送消息体
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("123412341234", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}