Netty学习_Netty框架入门教程:Netty入门之HelloWorld实现

时间:2019-05-26 12:58:00 来源:互联网 作者: 神秘的大神 字体:

我们可能都学过Socket通信/io/nio/aio等的编程。如果想把Socket真正的用于实际工作中去,那么还需要不断的完善、扩展和优化。比如很经典的Tcp读包写包问题,或者是数据接收的大小,实际的通信读取与应答的处理逻辑等等。当细节问题需要我们认真的去思考,而这些我们都需要大量的时间和精力,以及丰富的经验。

 

所以想学好socket通信不是件容易的事情。那么现在,我们就需要学习一门新的技术Netty

 

我们为什么选择Netty?原因是它简单。我们再也不需要去编写复杂的代码和逻辑去实现通信;我们再也不需要去考虑性能问题;我们再也不需要考虑编解码问题、半包读写等问题。这些强大的功能Netty已经帮我们实现了,我们只需要使用它即可!

 

Netty是目前最流行的NIO框架,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的。

 

Netty已经得到成百上千的商业/商用项目验证,如Hadoop的RPC框架Avro、以及我们之后学习的JMS框架,强大的RocketMQ、还有主流的分布式通信框架Dubbox等等。

 

Netty5废弃的原因
Netty5可能底层有一些小问题,可能版本更新太快了,然后他把Netty5起了一个分支叫Netty4.1。

 

Netty架构图


Netty特性

设计:各种传输类型,阻塞和非阻塞的套接字统一的API使用灵活简单但功能强大的线程模型无连接的DatagramSocket支持链逻辑,易于重用。

易于使用:提供大量的文档例子,处理依赖JDK1.6+,没有其他任何的依赖关系,某些功能依赖JDK1.7+,其他特定可能有相关依赖,但都是可选的!

性能:比Java APIS更好的吞吐量和更低的延迟,因为线程池和重用所以消耗较小的资源,尽量减少不必要的内存拷贝。

健壮性:健壮性连接快或慢或超载不会导致更多的内存溢出错误,在高速的网络环境中不会不公平的读或写

安全性:完整的SSL/TLS和StartTLS支持可以在OSGI等的受限制的环境中运行。

社区:版本发布频繁,社区活跃。

 

对应Netty的介绍就到这里,下面使用Netty框架实现一个HelloWorld。

 

第一步:下载Netty的jar包

这里使用的是Netty4.1版本。官网下载地址:https://netty.io/downloads.html

 

第二步:新建java工程

1、新建一个java工程,按照下图新建4个类

2、新建一个lib目录并把Netty的jar包拷贝到该目录

3、把jar包添加到环境变量

 

第三步:编写ServerHandler类代码,代码如下

 1 package netty.helloworld;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.ChannelHandlerContext;
 6 import io.netty.channel.ChannelInboundHandlerAdapter;
 7 
 8 public class ServerHandler extends ChannelInboundHandlerAdapter {
 9     @Override
10     public void channelActive(ChannelHandlerContext ctx) throws Exception {
11         System.out.println("server channel active... ");
12     }
13     
14     @Override
15     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
16             ByteBuf buf = (ByteBuf) msg;
17             byte[] req = new byte[buf.readableBytes()];
18             buf.readBytes(req);
19             String body = new String(req, "utf-8");
20             System.out.println("Server :" + body );
21             String response = "进行返回给客户端的响应:" + body;
22             ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
23     }
24 
25     @Override
26     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
27         System.out.println("读完了");
28         ctx.flush();
29     }
30 
31     @Override
32     public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
33         ctx.close();
34     }
35 }

 

第四步:编写Server类代码,代码如下

 1 package netty.helloworld;
 2 
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.ChannelOption;
 7 import io.netty.channel.EventLoopGroup;
 8 import io.netty.channel.nio.NioEventLoopGroup;
 9 import io.netty.channel.socket.SocketChannel;
10 import io.netty.channel.socket.nio.NioServerSocketChannel;
11 
12 public class Server {
13     public static void main(String[] args) throws Exception {
14         // 1 创建线两个程组 
15         // 一个是用于处理服务器端接收客户端连接的
16         // 一个是进行网络通信的(网络读写的)
17         EventLoopGroup pGroup = new NioEventLoopGroup();
18         EventLoopGroup cGroup = new NioEventLoopGroup();
19         
20         // 2 创建辅助工具类,用于服务器通道的一系列配置
21         ServerBootstrap b = new ServerBootstrap();
22         b.group(pGroup, cGroup)        // 绑定俩个线程组
23         .channel(NioServerSocketChannel.class)        // 指定NIO的模式
24         .option(ChannelOption.SO_BACKLOG, 1024)        // 设置tcp缓冲区
25         .option(ChannelOption.SO_SNDBUF, 32*1024)    // 设置发送缓冲大小
26         .option(ChannelOption.SO_RCVBUF, 32*1024)    // 这是接收缓冲大小
27         .option(ChannelOption.SO_KEEPALIVE, true)    // 保持连接
28         .childHandler(new ChannelInitializer<SocketChannel>() {
29             @Override
30             protected void initChannel(SocketChannel sc) throws Exception {
31                 // 3 在这里配置具体数据接收方法的处理
32                 sc.pipeline().addLast(new ServerHandler());
33             }
34         });
35         
36         // 4 进行绑定 
37         ChannelFuture cf1 = b.bind(8888).sync();
38         // 5 等待关闭
39         cf1.channel().closeFuture().sync();
40         pGroup.shutdownGracefully();
41         cGroup.shutdownGracefully();
42     }
43 }

 

第五步:编写ClientHandler类代码,代码如下

 1 package netty.helloworld;
 2 
 3 import io.netty.buffer.ByteBuf;
 4 import io.netty.channel.ChannelHandlerContext;
 5 import io.netty.channel.ChannelInboundHandlerAdapter;
 6 import io.netty.util.ReferenceCountUtil;
 7 
 8 public class ClientHandler extends ChannelInboundHandlerAdapter {
 9     @Override
10     public void channelActive(ChannelHandlerContext ctx) throws Exception {}
11 
12     @Override
13     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
14         try {
15             ByteBuf buf = (ByteBuf) msg;
16             
17             byte[] req = new byte[buf.readableBytes()];
18             buf.readBytes(req);
19             
20             String body = new String(req, "utf-8");
21             System.out.println("Client :" + body );
22         } finally {
23             ReferenceCountUtil.release(msg);
24         }
25     }
26 
27     @Override
28     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {}
29 
30     @Override
31     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
32         ctx.close();
33     }
34 }

 

第六步:编写Client类代码,代码如下

 1 package netty.helloworld;
 2 
 3 import io.netty.bootstrap.Bootstrap;
 4 import io.netty.buffer.Unpooled;
 5 import io.netty.channel.ChannelFuture;
 6 import io.netty.channel.ChannelInitializer;
 7 import io.netty.channel.EventLoopGroup;
 8 import io.netty.channel.nio.NioEventLoopGroup;
 9 import io.netty.channel.socket.SocketChannel;
10 import io.netty.channel.socket.nio.NioSocketChannel;
11 
12 public class Client {
13     public static void main(String[] args) throws Exception{
14         EventLoopGroup group = new NioEventLoopGroup();
15         Bootstrap b = new Bootstrap();
16         b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
17             @Override
18             protected void initChannel(SocketChannel sc) throws Exception {
19                 sc.pipeline().addLast(new ClientHandler());
20             }
21         });
22         
23         ChannelFuture cf1 = b.connect("127.0.0.1", 8888).syncUninterruptibly();
24         // 发送消息
25         byte[] msg = "发送第1条测试消息".getBytes();
26         cf1.channel().writeAndFlush(Unpooled.copiedBuffer(msg));
27         
28         // 等待关闭
29         cf1.channel().closeFuture().sync();
30         group.shutdownGracefully();
31     }
32 }

 

第七步:启动Server服务

 

 

最后一步:启动客户端

 

 

控制台输出

 

关于Netty框架学习的第一节课就讲到这里,其他更多关于Netty方面的教程后续会陆续更新!!

end -- 1346ac475e98aed

需要索取完整源码或者其他任何有关技术问题和疑问,直接wxhaox