1. Netty 示例
1.1. 简单的 Echo 服务器
这里,我们直接使用Netty作为独立的进程启动
1.1.1. Netty 依赖
maven依赖如下:
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.2.7.Final</version>
</dependency>
1.1.2. Netty Server
这里我们直接通过Netty监听8080端口,作为服务端启动:
- EchoServer.java
import com.huawei.athena.netty.handler.EchoServerHandler;
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 io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;import java.util.concurrent.atomic.AtomicBoolean;@Slf4j
public class EchoServer {private final int port = 8080;private EventLoopGroup bossGroup;private EventLoopGroup workerGroup;private ChannelFuture serverChannelFuture;private final AtomicBoolean running = new AtomicBoolean(false);public void start() {if (!running.compareAndSet(false, true)) {log.info("the server is running");return;}// 创建事件循环组bossGroup = new NioEventLoopGroup(); // 用于接受连接workerGroup = new NioEventLoopGroup(); // 用于处理连接try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 使用NIO传输通道.option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ch.pipeline().addLast(new EchoServerHandler());}}).option(ChannelOption.SO_BACKLOG, 128) // 服务器套接字选项.childOption(ChannelOption.SO_KEEPALIVE, true); // 客户端套接字选项// 绑定端口并开始接收连接serverChannelFuture = b.bind(port).sync();log.info("Echo服务器启动,监听端口: {}", port);// 等待服务器套接字关闭} catch (InterruptedException e) {log.error("can't start the netty server, ", e);stop();}}public void stop() {if (!running.compareAndSet(true, false)) {log.info("the server is running");return;}log.info("Shutting down Echo server...");// 先关闭服务器通道if (serverChannelFuture != null) {serverChannelFuture.channel().close().awaitUninterruptibly();}// 优雅关闭EventLoopGroupif (workerGroup != null) {workerGroup.shutdownGracefully();}if (bossGroup != null) {bossGroup.shutdownGracefully();}log.info("Echo server shutdown complete");}
}
1.1.3. 服务端回显处理
这里,我们实现了一个简单的业务逻辑,即收到客户端的数据后,不做任何处理,直接原样发送给客户端:
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;@Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ctx.write(msg);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) {ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();}
}
1.1.4. 主程序
public class NettyApp {public static void main(String [] args) {new EchoServer().start();}
}
1.1.5. 验证
服务端启动进程NettyApp后,我们可以通过telnet命令与服务器交互:
telnet localhost 8008
如果一切正常,当你在控制台上输入字符后,你应该能看到它原样的输出,类似如下打印:
12233445566778899