我们可能都学过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类代码,代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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类代码,代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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类代码,代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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类代码,代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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