共计 2956 个字符,预计需要花费 8 分钟才能阅读完成。
Netty学习:一、概述
前言
九月不知不觉就到了,之前和导师定好日期,打算10月开始准备毕业设计,在此之前我一直不知道自己的本科毕业设计要做什么个玩意出来。我本可以像绝大多数毕业生一样,随便选一套高大尚的技术栈然后写一个xxx管理系统把本科毕业设计水过去的,顺利毕业,然而仔细想想我的大学时光,我每天基本都是和程序代码打交道,其实并不是很想让我的毕设成为一个水项目。
在我冷静下来并回想我学计算机以来遇到的对我帮助最大的技术,网络代理是毫无疑问排第一的。正是因为学会了网络代理,我才用上了Google、逛上了Github、在YouTube上看教学视频、学习项目文档并使用各类项目、使用国外服务器搭建我的个人博客和各种各样的开源项目,网络代理打破我与世界的隔阂,影响了我整个大学期间的学习方式。
"要不我的毕设选一个网络代理方向上的课题吧?" 我想到我在平常开发或学习时用到的一些微服务或分布式组件,貌似都涉及到网络通信,都涉及到Netty。Netty是什么?Java网络开发中的Spring!
概述
什么是Netty?
Netty project - an event-driven asynchronous network application framework
Netty是一个基于事件驱动的异步网络框架,是基于NIO实现的一个网络框架,可以快速地开发协议服务器和客户端。
作者
Trustin Lee,韩国人。除Netty外,还参与开发Apache的Mina。
作者博客:https://t.motd.kr/
Netty的地位
Netty在Java网络编程中的地位好比:Spring在Java EE开发中的地位。
很多组件或框架都用到了Netty:
- Cassandra: NoSQL数据库;
- Spark: 大数据分布式计算框架;
- Hadoop: 大数据分布式存储框架;
- RocketMQ:阿里开源的消息队列;
- ElasticSearch:搜索引擎;
- gRPC:rpc框架;
- Dubbo:rpc框架;
- Spring WebFlux: Spring 异步网络模型
- Zookeeper:分布式协调框架
优势
Netty基于NIO实现,解决了NIO开发的问题:
- 工作量大,Bug多
- 需要自己构建协议
- 解决TCP传输问题,如粘包、半包;
- epoll空轮询,CPU易100%;
- 对API进行增强,更易使用;
快速入门
实现一个简单的Echo应用。Echo应用就是构建一个服务端,客户端向服务端发送一段数据,服务端接收到后再将该数据返回。
package me.pgthinker;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.CharsetUtil;
/**
* @Project: me.pgthinker
* @Author: pgthinker
* @GitHub: https://github.com/ningning0111
* @Date: 2024/9/1 14:27
* @Description:
*/
public class EchoServer {
private final static Integer port = 8778;
public static void main(String[] args) throws InterruptedException {
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
ByteBuf resp = Unpooled.copiedBuffer("服务端返回的消息:" + byteBuf.toString(CharsetUtil.UTF_8), CharsetUtil.UTF_8);
channelHandlerContext.writeAndFlush(resp);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("连接成功!\n", CharsetUtil.UTF_8));
}
});
}
}).bind(port);
}
}
上面的代码是回声服务程序的服务端,当建立连接时,服务端会监听channel的读事件,从channel中读取数据,同时将数据写回给客户端。
new ServerBootstrap()
: 创建一个启动器,这个启动器需要将Netty的各种组件进行组装;group
用于配置NIO的线程池,处理IO操作;channel
用于指定使用NIO处理哪类连接,在案例中我们处理TCP套接字;childHandler
: 定义在接收连接后用于处理每个连接的处理器。在上述代码中ChanelIntializer
用于初始化SocketCannel
.SimpleChannelInboundHandler
: 用于处理收到消息的抽象类。参数类型ByteBuf
表示处理的参数类型。channelRead0
方法:当服务器收到客户端发送的数据时就会被调用。上例中我们将收到的数据后构建新的ByteBuf对象并重新发送回去。channelActive
方法:通道激活后调用,通常在客户端建立连接成功时调用。
bind
: 用于指定服务端绑定的端口号。
测试
使用telnet [ip] [端口号]
建立连接: