1. 需求
- 客户端向服务端发送信息,服务端将信息打印
- 客户端接收键盘输入到信息循环向服务端发送信息
- 客户端接收键盘输入‘q’时关闭
2.服务端代码
import io.netty.bootstrap.ServerBootstrap;`在这里插入代码片`
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.Charset;
@Slf4j
public class Server {
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup(2);
ServerBootstrap serverBootstrap = new ServerBootstrap()
.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast("handler1", new ChannelInboundHandlerAdapter() {
@Override // ByteBuf
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
String s = buf.toString(Charset.defaultCharset());
log.debug(s);
}
});
}
});
ChannelFuture channelFuture = serverBootstrap.bind(8080);
}
}
客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.util.Scanner;
@Slf4j
public class Client {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup group = new NioEventLoopGroup();
ChannelFuture channelFuture = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override // 在连接建立后被调用
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
})
.connect(new InetSocketAddress("localhost", 8080));
System.out.println(channelFuture.getClass());
Channel channel = channelFuture.sync().channel();
log.debug("{}", channel);
new Thread(()->{
Scanner scanner = new Scanner(System.in);
while (true) {
String line = scanner.nextLine();
if ("q".equals(line)) {
channel.close(); // close 异步操作 1s 之后
break;
}
channel.writeAndFlush(line);
}
}, "input").start();
// 获取 CloseFuture 对象, 1) 方法1 同步处理关闭, 2) 方法2 异步处理关闭
ChannelFuture closeFuture = channel.closeFuture();
/*
方法一
log.debug("waiting close...");
closeFuture.sync();
log.debug("处理关闭之后的操作");
group.shutdownGracefully();
*/
// 方法二
closeFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
log.debug("处理关闭之后的操作");
group.shutdownGracefully();// 优雅关闭
}
});
// 方法三:拉姆达表达式简化方法二
//closeFuture.addListener((ChannelFutureListener) future -> {
// log.debug("处理关闭之后的操作");
// group.shutdownGracefully();
//});
}
}
重点关注方法二
channel.closeFuture()
获取处理closeFuture
对象,使用其.addListener()
方法添加一个ChannelFutureListener
监听器,在关闭操作完成后执行相应的操作,然后调用group.shutdownGracefully()
优雅地关闭事件循环组。
运行
依次运行服务端和客户端,客户端输入:
服务端输出: