1.Netty服务器在6668端口监听,客户端能发送消息给服务器“hello 服务器”,服务器可以回复消息给客户端“hello,客户端”
服务器端代码:
public class NettyServer {
public static void main(String[] args) throws Exception {
//创建bossGroup,workGroup
//bossGroup只处理连接请求,真正的和客户的业务处理会交给workGroup完成
// 两个都是无限循环
//bossGroup,workerGroup含有的子线程(NioEventLoopGroup)默认有cpu核数*2
// 指定bossgroup一个线程
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 创建服务器端的启动对象,配置参数
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)//设置两个线程组
.channel(NioServerSocketChannel.class)//服务器端通道
.option(ChannelOption.SO_BACKLOG, 128)//设置线程队列得到的连接数
.childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动链接状态
.childHandler(new ChannelInitializer<SocketChannel>() {//匿名创建一个测试对象
//给pipeline设置处理器
@Override
protected void initChannel(SocketChannel socketChannel) {
//给我们的workerGroup的EventLoop对应的管道设置处理器
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("........服务器 is ready.....");
// 绑定一个端口并且同步,生成一个channelFuture对象
//启动服务器并绑定端口
ChannelFuture cf = bootstrap.bind(6668).sync();
//对关闭通道进行监听
cf.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
/**
* 1.我们自定义一个handler,需要继承netty规定好的某个handlerAdapter
* 2.这时我们自定义一个ehandler才能称为一个handler
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
//读取数据事件(这里我们可以读取客户端发送的消息
/**
* channelHandlerContext上下文对象含有:pipeline,通道channel,地址等信息
* Object msg:就是客户端发送的数据
*/
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception{
System.out.println("服务器读取数据线程:"+Thread.currentThread().getName());
System.out.println("server ctx = "+ctx);
//将msg转为一个byteBuf,这个ByteBuf是Netty提供的,不同于NIO的ByteBuffer
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发送消息是:"+buf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址:"+ctx.channel().remoteAddress());
/**
* 比如这里我们有个非常耗时的业务,我们需要异步执行,需要提交到该channel对应的NioEvention的taskQueue中
*/
// 解决方案1:用户自定义的程序任务
ctx.channel().eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10 * 1000);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端喵2", CharsetUtil.UTF_8));
}catch (Exception e){
e.printStackTrace();
}
}
});
System.out.println("go on ......");
// 解决方案2:将任务提交到scheduleTaskQueue中
ctx.channel().eventLoop().schedule(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5 * 1000);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello 客户端喵2", CharsetUtil.UTF_8));
}catch (Exception e){
e.printStackTrace();
}
}
},20, TimeUnit.MILLISECONDS);
}
// 数据读取完毕
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{
//writeAndFlush将数据写入到缓存,并刷新
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 Exception{
//客户端需要一个事件循环组
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
//创建客户端启动对象
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("客户端 ok ,,,,,");
ChannelFuture channelFuture = bootstrap.connect("localhost", 6668).sync();
channelFuture.channel().closeFuture().sync();
}finally {
eventExecutors.shutdownGracefully();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
System.out.println("client "+ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello, server: ", CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务器回复的消息:"+buf.toString(CharsetUtil.UTF_8));
System.out.println("服务器地址:"+ctx.channel().remoteAddress());
}
//处理异常,一般是需要关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx , Throwable cause) throws Exception{
ctx.close();
}
}