一、简介
Netty 是一个客户端/服务器框架,它提供了 NIO 网络的简化层。这使得它成为创建低级非阻塞网络应用程序的良好候选者。先看看 Netty 框架的主要亮点:
-
Netty 比普通的 Java NIO 更易于使用
-
只需一个依赖即可获得整个框架(例如使用 Maven)
-
具有更好的吞吐量和更低的延迟。由于其内部资源池,它还具有可扩展性。
-
完整的 SSL/TLS 和 StartTLS 支持。
二、开始
2.1、在 Maven 工程中添加依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.52.Final</version>
</dependency>
2.2、创建服务端代码
import java.util.ArrayList;
import java.util.List;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public final class NettyServer {
static final int PORT = 8888;
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new StringDecoder());
p.addLast(new StringEncoder());
p.addLast(new ServerHandler());
}
});
ChannelFuture f = b.bind(PORT).sync();
//System.out.println("Netty 服务已启动.");
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
@Sharable
class ServerHandler extends SimpleChannelInboundHandler<String> {
static final List<Channel> channels = new ArrayList<Channel>();
@Override
public void channelActive(final ChannelHandlerContext ctx) {
channels.add(ctx.channel());
}
@Override
public void channelRead(ChannelHandlerContext ctx, String msg) throws Exception {
for (Channel c : channels) {
c.writeAndFlush("Hello " + msg + '\n');
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
}
(1)示例使用了两个 EventLoopGroup。第一个是 boostrap 服务器,第二个是 Worker Group。这是一种常见的最佳实践,以便您可以针对高负载调整特定组并检测瓶颈。
(2)请注意 Handler 上的 @Sharable
注解:这意味着您可以注册并与多个客户端共享它。
2.3、创建客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public final class NettyClient {
static final String HOST = "127.0.0.1";
static final int PORT = 8888;
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new StringDecoder());
p.addLast(new StringEncoder());
p.addLast(new ClientHandler());
}
});
ChannelFuture f = b.connect(HOST, PORT).sync();
String input = "您好!";
Channel channel = f.sync().channel();
channel.writeAndFlush(input);
channel.flush();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
class ClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("来自服务端的消息: " + msg);
}
}
2.4、运行说明
使用 Maven 或 开发工具先运行服务端,然后再运行客户端即可。
两个都是 main 类,你可以考虑在 maven 中配置引导,有智能开发工具的就不用。
一般情况下,业务逻辑都在 ChannelInboundHandler 处编写!
三、扩展知识
3.1、为什么使用 telnet 连接后,输入一个字母它就输出两个出来
非常有可能你使用 Windows 的 telnet 来测试,传说中是 '\r\n‘ 和 '\n' 的原因,但这个问题我还是建议打开 linux 版的 telnet,或其它一些网络工具。其实都自己写客户端了,先不用考虑这个了。
3.2、Maven 如何运行指定 main 类
在 pom 中添加如下类似片断:(注意 mainClass 要跟你的包路径一致)
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>com.example.MainClass</mainClass>
</configuration>
</plugin>
</plugins>
</build>
3.3、还有一个 mina,用哪个好?
Netty 和 MINA 都是Java平台上的高性能网络通信框架,它们都提供了异步非阻塞的API来简化网络程序的开发。(一般首选 netty,从设计、文档、性能、社区等相比较的结果。)
Netty
- 性能:Netty是目前业界公认的高性能网络编程框架之一,它的性能通常被认为比MINA更好。
- 社区和支持:Netty有一个非常活跃的社区,很多知名的开源项目(如Apache Dubbo、gRPC)都在使用Netty。因此,如果你在开发过程中遇到问题,更容易找到解决方案或者获得帮助。
- 文档和资源:Netty的文档和网络上的资源比MINA更丰富,这使得学习和使用Netty相对容易一些。
- 功能和灵活性:Netty提供了更多的功能和更高的灵活性,它支持更多的协议和数据处理方式。
MINA
- 简单易用:MINA的设计初衷是简单易用,它提供了一套比较简洁的API,对于一些不需要极致性能的应用,MINA的简单性可能会是一个优势。
- 轻量级:MINA相对于Netty来说更轻量级,如果你的项目对资源消耗有严格的限制,MINA可能是一个不错的选择。
- 社区和支持:虽然MINA的社区不如Netty活跃,但它仍然有一定的用户基础和社区支持。
总结
- 如果你需要极高的性能、更多的功能和更好的社区支持,Netty可能是更好的选择。
- 如果你的项目相对简单,对性能的要求不是非常高,或者你更偏好简单易用的框架,MINA可能会更适合你。