Netty学习之路!记录每周学习到的netty!
LZ为什么要学习Netty呢,其实LZ自己也不知道。
进入正题;
Netty 是由NIO进化而来的,它是一个很底层的框架,底层基于NIO。而NIO又是IO的一个升级。
所以他们的顺序是IO,NIO,Netty。
Netty他是一个通讯的框架。
其实有很多很多的框架,技术底层都用到了Netty,这个可以在Netty官网上看到。
举一些知名的项目也是前三的:Akka,Apache BookKeeper,Apache Cassandra,这些项目都是Apache的。项目的具体我就不做多介绍了,(PS:其实LZ也不知道,所以介绍不了 Hhhhhhh)不过大家可以去Netty的官网上面看看。
Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端,Netty是一个NIO客户端服务器的框架,可以快速的开发协议服务器和客户端登网络应用程序。极大的简化了TCP和UDP套接字服务器等网络编程。Netty经过精心的设计,具有很多丰富的协议,如:FTP,SMTP,HTTP以及各种基于二进制和基于文本的传统协议,因此,Nett'y成功地找到了一种不在被妥协的情况下实现易于开发,性能,稳定性和灵活方法的方法。(PS:Netty里面封装了各种协议,各种API,基本上能说得出口的协议,Netty基本都集成了。说白话就是简易了开发,让我们程序员更轻松。)
关于性能方面:
1:更高的吞吐量
2:减少资源消耗
3:最小化不必要的内存复制
关于安全方面:
完整的SSL/TLS和StartTLS的支持
下面的是官网的一张图:由于LZ看的不是很透彻,所以就不做讲解了。
接下来进入代码环节:
首先导入包:
"io.netty:netty-all:4.1.10.Final"
LZ这里用的是Gradle,所以和maven的不一样,下面贴一下Maven的:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.10.Final</version>
</dependency>
首先我们来编写一个Netty的服务器:
public static void main(String[] args) throws Exception {
// 从客户端接收链接,不做处理
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 接收链接 分发链接
EventLoopGroup worketGroup = new NioEventLoopGroup();
try {
// 启动服务端
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, worketGroup)
// 通道 通过反射的方式
.channel(NioServerSocketChannel.class)
// 指定日志级别
.handler(new LoggingHandler(LogLevel.INFO))
// 定义处理器
.childHandler(new WebSocketChannelInitializer());
ChannelFuture sync = bootstrap.bind(new InetSocketAddress(8899)).sync();
sync.channel().closeFuture().sync();
} finally {
// 优雅关闭
bossGroup.shutdownGracefully();
worketGroup.shutdownGracefully();
}
}
LZ就不过多解释:代码都写好注释了。
然后就是书写初始化类(PS:看继承的类大家就应该都知道了,这是一个初始化的类): 里面的方法LZ就不过多介绍,不然篇幅太长;
public class MyClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// AddLast的意思是添加到末尾 主要是解码
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
// 添加砸门自己定义的处理器
pipeline.addLast(new MyServerHandler());
}
}
之后当然是书写自己定义的处理器类
public class MyServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 打印收到的语句
System.out.println(ctx.channel().remoteAddress()+","+msg);
// 服务端像客户端返回一段话 加上UUID
ctx.channel().writeAndFlush("form server:"+ UUID.randomUUID());
}
}
到这里服务端基本算是写完了,接下来就是书写客户端。
public static void main(String[] args) throws InterruptedException {
EventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors)
.channel(NioSocketChannel.class)
.handler(new MyClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync();
channelFuture.channel().closeFuture().sync();
}finally {
eventExecutors.shutdownGracefully();
}
}
客户端这里为什么是创建一个呢。目前呢不要太在乎细节,LZ后面会讲。
接下来是书写客户端初始类:
public class MyClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new MyClientHandler());
}
}
在下面就是客户端处理器类:
public class MyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(ctx.channel().remoteAddress());
System.out.println("client output" + msg);
// 向服务端返回时间
ctx.writeAndFlush("from client"+ LocalDateTime.now());
}
}
现在一个很简单的程序就算是写完了。
其实大家仔细一点都看出来了,服务端的代码和客户端的代码基本差不多,大同小异。
具体的运行结果LZ就不做过多的演示了。
以后LZ会将每周学到的Netty知识,写到博客中。