# 基本概念
- 服务端:使用Netty编写后端,用于处理客户端发送的消息。
- 客户端:连接到Netty服务器端,向服务器端发送消息。
handler
:Netty通过一个个handler来处理业务,也就是每条消息会经过n(n≥0)个handler。ByteBuf
:netty默认只解析ByteBuf类型的数据,通过处理或经过handler处理后才能识别字符串等其他类型数据。channel
:可以有多个客户端连接到Netty,每个连接叫做channel,拿到channel对象就可以通过channel发送或接收数据。
# 创建处理消息的handler
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.HashSet;
import java.util.Set;
public class DiscardServerH11andler extends ChannelInboundHandlerAdapter {
static Set<Channel> channelList = new HashSet<>();
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
boolean add = channelList.add(ctx.channel());
if (add) {
System.out.println("有新连接,当前连接数:" + channelList.size());
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
channelList.remove(ctx.channel());
System.out.println("客户端断开连接,当前连接数:" + channelList.size());
}
}
# 创建服务器端
这里基本就是模板代码,主要是编写handler责任链来处理客户端连接、消息的收发等。
import com.xk857.netty.my.handler.DiscardServerHandler;
import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class DiscardServer {
// 端口号
private int port;
public DiscardServer(int port) {
this.port = port;
}
public void run() throws Exception {
// 1.创建一个单线程的 EventLoopGroup 作为 boss 线程组,用于接受客户端连接。
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 2.创建默认数目的 EventLoopGroup 作为 worker 线程组,用于处理网络 IO 事件。
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 3.创建服务端启动对象。
ServerBootstrap b = new ServerBootstrap();
// 4.配置参数,设置两个线程组,指定使用NIO模式,添加若干个自定义的 ChannelHandler
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
Charset utf = StandardCharsets.UTF_8;
ch.pipeline().addLast(new DiscardServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128) // 充分利用操作系统的队列(backlog)数,即客户端的请求接受队列
.childOption(ChannelOption.SO_KEEPALIVE, true);// 保持长连接状态
// 绑定指定的端口来监听客户端的连接请求。sync 方法会阻塞,直到服务器完成绑定才会返回。
ChannelFuture f = b.bind(port).sync();
System.out.println("tcp start success");
// 等待服务端监听端口关闭后退出程序。closeFuture 方法会阻塞直到服务器 Channel 关闭,然后才会退出。
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
# 启动服务器
public class ChatStarter {
public static void main(String[] args) {
try {
new DiscardServer(9001).run();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
打开windows的命令行窗口,输入telnet 127.0.0.1 9001
,观察控制台打印数据。