什么是 Netty?
Netty 是 jboss 提供的一个 Java 开源框架,Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可用性的网络服务器和客户端程序。也就是说 Netty 是一个基于 NIO 的编程框架,使用 Netty 可以快速的开发出一个网络应用。
由于 Java 自带的 NIO API 使用起来非常复杂,并且还可能出现 Epoll Bug,这使得我们使用原生的 NIO 来进行网络编程存在很大的难度且非常耗时。但是 Netty 良好的设计可以使开发人员快速高效的进行网络应用开发。
Netty 入门
搭建项目
首先需要搭建一个普通的 Maven 项目,JDK 版本为 JDK8。
引入 Netty 依赖
由于 Netty5 已经被废弃,目前最新的 Netty 版本是 Netty4。
1 2 3 4 5
| <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.67.Final</version> </dependency>
|
搭建 Netty 服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| public class NettyServer {
public static void main(String[] args) throws Exception { NettyServer nettyServer = new NettyServer(); nettyServer.start(12345); }
public void start(int port) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(group); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.localAddress(new InetSocketAddress(port)); serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel channel) { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast("StringDecoder", new StringDecoder()); pipeline.addLast("StringEncoder", new StringEncoder()); pipeline.addLast("ServerHandler", new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { Channel channel = ctx.channel(); System.out.println("server receive UserToken[" + channel.id().asLongText() + "] msg ==> " + msg); }
@Override public void channelActive(ChannelHandlerContext ctx) { Channel channel = ctx.channel(); System.out.println("UserToken[" + channel.id().asLongText() + "] 创建链接"); final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("The server created a link!", StandardCharsets.UTF_8)); ctx.writeAndFlush(buf.duplicate()); }
@Override public void channelInactive(ChannelHandlerContext ctx) { Channel channel = ctx.channel(); System.out.println("UserToken[" + channel.id().asLongText() + "] 断开链接"); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { Channel channel = ctx.channel(); System.out.println("UserToken[" + channel.id().asLongText() + "] 发生异常"); } }); } }); ChannelFuture channelFuture = serverBootstrap.bind().sync(); channelFuture.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully().sync(); } } }
|
搭建 Netty 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class NettyClient {
public static void main(String[] args) { NettyClient nettyClient = new NettyClient(); nettyClient.start("127.0.0.1", 12345); }
public void start(String host, int port) { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap clientBootstrap = new Bootstrap(); clientBootstrap.group(group); clientBootstrap.channel(NioSocketChannel.class); clientBootstrap.handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel channel) { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast("StringDecoder", new StringDecoder()); pipeline.addLast("StringEncoder", new StringEncoder()); pipeline.addLast("ClientHandler", new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("client receive msg ==> " + msg.toString()); } }); } });
ChannelFuture channelFuture = clientBootstrap.connect(host, port); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.println("Please enter:"); String msg = bufferedReader.readLine(); channelFuture.channel().writeAndFlush(msg); } } catch (Exception e) { e.printStackTrace(); } finally { group.shutdownGracefully(); } } }
|
启动项目
分别启动 NettyServer 和 NettyClient 的 main 方法,服务器和客户端即可进行简单的通讯。