第 3 章 运行第一个 Netty 服务
3.1 先让它跑起来
进入随书工程的 examples 目录。执行:
mvn test
mvn compile exec:java -Dexec.mainClass=book.LineServer第一次下载依赖需要联网。测试完成后启动服务器,看到以下文字说明监听已成功:
LISTENING 8080
保留这个终端,再打开第二个终端,进入同一个 examples 目录:
mvn compile exec:java -Dexec.mainClass=book.LineClient客户端应依次输出:
收到:你好,Netty
再见
客户端先发送一条普通消息,再发送 quit。服务器写出“再见”,待这次写操作完成后关闭连接。关闭的是这条客户端连接,服务器仍然继续监听。
在服务器终端按 Ctrl+C 可以停止进程。示例中的 finally 负责程序正常退出该代码路径时清理资源;它不是完整的进程信号停机方案,第 13 章会讨论生产服务的停机顺序。
3.2 用不同端口试一次
如果 8080 已被占用,两个终端都改用 9090:
mvn compile exec:java -Dexec.mainClass=book.LineServer -Dexec.args=9090
mvn compile exec:java -Dexec.mainClass=book.LineClient -Dexec.args=9090这两条命令分别在两个终端执行,先运行服务器。客户端参数也必须改,否则它仍会寻找 8080。
3.3 服务器的骨架
主线结构如下,完整可复制源码在附录 A:
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
try {
Channel server = new ServerBootstrap()
.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(/* 为每条新连接安装处理器 */)
.bind("127.0.0.1", 8080).sync().channel();
server.closeFuture().sync();
} finally {
boss.shutdownGracefully().sync();
worker.shutdownGracefully().sync();
}这段是结构说明,含有占位注释,运行时请用附录完整版本。boss 接收新连接,worker 处理已建立连接的 I/O。ServerBootstrap 负责组装启动配置;bind 发起监听;sync 等待异步操作完成;closeFuture 在监听 Channel 关闭时完成。
NioServerSocketChannel 表示基于 Java NIO 的监听通道。childHandler 配置的是接入后的连接。不要与 handler 混淆:服务器上的 handler 面向监听通道,childHandler 面向接受到的子通道。[1]
3.4 先形成一个整体图像
客户端发送字节
↓
操作系统接收 → worker 的 EventLoop
↓
按行切分 → UTF-8 解码 → 业务处理
↓
客户端接收 ← 网络发送 ← UTF-8 编码
如果你现在只记住“Netty 把网络事件交给我写的处理器”,就已经足够继续。
小练习: 客户端运行结束后,服务器为什么没有跟着退出?