netty初识
netty是什么?
Netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,可以快速轻松地开发高性能、高可靠性协议服务器和客户端之类的网络应用程序。它大大简化了网络编程流程,如TCP和UDP套接字服务器。
netty特性
并发高
对比于BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。
如图:


在BIO中,等待客户端发数据这个过程是阻塞的,这样就造成了一个线程只能处理一个请求的情况,而机器能支持的最大线程数是有限的,这就是为什么BIO不能支持高并发的原因。
而NIO中,当一个Socket建立好之后,Thread并不会阻塞去接受这个Socket,而是将这个请求交给Selector,Selector会不断的去遍历所有的Socket,一旦有一个Socket建立完成,他会通知Thread,然后Thread处理完数据再返回给客户端——这个过程是阻塞的,这样就能让一个Thread处理更多的请求了。
传输快
封装好
编写netty的"Hello World"

2.创建Server 服务端
Netty创建全部都是实现自AbstractBootstrap。客户端的是Bootstrap,服务端的则是ServerBootstrap。
2.1 创建一个 HelloServer
/**
* Author: xinyuzhuang
* Date: 2018/7/17 14:15
* History:
* <author> <time> <version> <desc>
* 作者姓名 修改时间 版本号 描述
*/
package com.daojia;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
*created by xinyuzhuang
*/
public class NettyServer1 {
public static void main(String[] args) {
//用于处理服务器端接收客户端连接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//进行网络通信
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//辅助工具类,用于服务器通道的一系列配置
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup) //绑定两个线程
.channel(NioServerSocketChannel.class) //制定nio的模式
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
/*系统自带定长解决粘包问题
socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(40));
系统自带字符串解码
socketChannel.pipeline().addLast(new StringDecoder());
socketChannel.pipeline().addLast(new InboundHandler());*/
}
}).option(ChannelOption.SO_BACKLOG,128) //设置tcp缓冲区
.option(ChannelOption.SO_SNDBUF, 32 * 1024) //设置发送数据缓冲大小
.option(ChannelOption.SO_RCVBUF, 32 * 1024) //设置接受数据缓冲大小
.childOption(ChannelOption.SO_KEEPALIVE, true); //保持连接
ChannelFuture future = bootstrap.bind(8000).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
private static class InboundHandler extends ChannelInboundHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] data = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(data);
String request = new String(data,"utf-8");
System.out.println("server:"+request);
//反馈给客户端
ctx.writeAndFlush(Unpooled.copiedBuffer("sachjscfsjcssjcs".getBytes()));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
EventLoopGroup 是在4.x版本中提出来的一个新概念。用于channel的管理。服务端需要两个。和3.x版本一样,一个是boss线程一个是worker线程。 server主要 目的绑定客户端端口号。
FixedLengthFrameDecoder()和 StringDecoder()是系统自带的方法,InboundHandler()自己的Handler用于写自己的处理逻辑,在channelHandlerContent自带一个writeAndFlush方法,方法的作用是写入Buffer并刷入。
注意:在3.x版本中此处有很大区别。在3.x版本中write()方法是自动flush的。在4.x版本的前面几个版本也是一样的。但是在4.0.9之后修改为WriteAndFlush。普通的write方法将不会发送消息。需要手动在write之后flush()一次。
channelRead0 在这里的作用是类似于3.x版本的messageReceived()。可以当做是每一次收到消息是触发。
2.2 创建一个 HelloClient
/** * Author: xinyuzhuang * Date: 2018/7/17 15:06 * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.daijia.dmqclienrt; import com.sun.org.apache.bcel.internal.classfile.ConstantValue; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.util.ReferenceCountUtil; /** *created by xinyuzhuang */ public class NettyClient1 { public static void main(String[] args) { NioEventLoopGroup workerGroup = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); try { bootstrap.group(workerGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new ClientInboundHandler()); } }); ChannelFuture future = bootstrap.connect("127.0.0.1", 8000).sync(); future.channel().writeAndFlush(Unpooled.copiedBuffer("让我机动车道".getBytes())); future.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); } } private static class ClientInboundHandler extends ChannelInboundHandlerAdapter{ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] data = new byte[buf.readableBytes()]; buf.readBytes(data); System.out.println("Client:"+new String(data,"utf-8")); //ctx.writeAndFlush(Unpooled.copiedBuffer("基础撒即可产生".getBytes())); ReferenceCountUtil.release(msg); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { byte[] req = "金粉世家开放式空间".getBytes(); ByteBuf message = null; for (int i = 0; i < 100; i++) { message = Unpooled.buffer(req.length); message.writeBytes(req); ctx.writeAndFlush(message); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } }
2.3 HandlerInitializer详解
Handler在Netty中是一个比较重要的概念。有着相当重要的作用。相比于Netty的底层。我们接触更多的应该是他的Handler。在这里我将它剥离出来单独解释。
ChannelInitializer<SocketChannel>继承ChannelInboundHandlerAdapter类,需要我们实现一个initChannel()方法。我们定义的handler就是写在这里面。
在最开始的地方定义了一个FixedLengthFrameDecoder类。按直接翻译就是基于字符定长的帧解码器。再一次感觉框架的作者的命名,好直接好简单。详细的内容我们在后面的文章中在为大家详细的解释。
下面的则是StringDecoder 和StringEncoder。字符串解码器和字符串编码器。
最后面则是我们自己的逻辑。服务/客户端逻辑是在消息解码之后处理的。然后服务/客户端返回相关消息则是需要对消息进行相对应的编码。最终才是以二进制数据流的形势发送给服务/客户端的。
注:
ChannelInBoundHandler负责数据进入并在ChannelPipeline中按照从上至下的顺序查找调用相应的InBoundHandler。
ChannelOutBoundHandler负责数据出去并在ChannelPipeline中按照从下至上的顺序查找调用相应的OutBoundHandler。
Netty其实本质上就是Reactor模式的实现,Selector作为多路复用器,EventLoop作为转发器,Pipeline作为事件处理器。但是和一般的Reactor不同的是,Netty使用串行化实现,并在Pipeline中使用了责任链模式。

浙公网安备 33010602011771号