Netty
介绍:是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,它提供了
简单易用的api从网络处理代码中解耦业务逻辑。Netty完全基于NIO实现的,Netty是异步的。
Netty健壮性、功能、性能、可定制性和可扩展性在同类框架都是首屈一指的。
网站:http://ifeve.com/netty5-user-guide/
Netty实现通信的步骤:
1:创建两个NIO线程组,一个用于网络事件处理(接受客户端的连接),另一个则进行网络
通信的读写。
2:创建一个ServerBootstarp对象,配置Netty的一系列参数,如传出去数据的缓存
3:创建一个实际处理数据的类ChannelInitializer,进行初始化的准备工作,比如设置接受传出
数据的字符集、格式、已经实际处理数据的接口
4:绑定端口,执行同步阻塞方法等待服务器端口启动即可
Netty对Byte实现了优化,因为有两个指针
TCP粘包、拆包问题
1、应用程序write写入的字节大小大于套接口发送缓冲区的大小
2、进行MSS大小的TCP分段
3、以太网帧的payload大于MTU进行IP分片
TCP粘包、拆包解决方案
1、消息定长
2、在包尾部增加特殊字符进行分割,例如回车
3、将消息分为消息头和消息体,在消息头中包含表示消息总总长度的字段,然后进行业务处理
Hetty解决粘包、拆包问题
1、分隔符 DelimiterBasedFrameDecoder
在Server类和Client类中initChannel方法中
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
//设置字符串形式的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
Server类
public class Server {
public static void main(String[] args) throws InterruptedException {
//第一个线程组 是用于接收Client端连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
//第二个线程组 适用于实际的业务处理操作的
EventLoopGroup workerGroup = new NioEventLoopGroup();
//创建一个辅助类Bootstrap,就是对我们Server进行一系列的配置
ServerBootstrap b = new ServerBootstrap(); // (2)
//把两个工作线程组加入进来
b.group(bossGroup, workerGroup)
//我要指定使用NioserverSocketChannel这种类型的通道
.channel(NioServerSocketChannel.class)
//一定要使用childHandler去绑定具体的事件处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// TODO Auto-generated method stub
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture f = b.bind(8765).sync();
f.channel().closeFuture().sync();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
ServerHandler类
public class ServerHandler extends ChannelHandlerAdapter{
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String request = (String)msg;
System.out.println("Server:"+request);
//写给客户端
String response = "我是反馈的信息$_";
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()))
.addListener(ChannelFutureListener.CLOSE);
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
cause.printStackTrace();
ctx.close();
}
}
Client类
public class Client {
public static void main(String[] args) throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// TODO Auto-generated method stub
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf1 = b.connect("127.0.0.1",8765).sync();
cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));
cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));
cf1.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
ClientHandler类
public class ClientHandler extends ChannelHandlerAdapter{
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
//do something msg
String data = (String)msg;
System.out.println("Client: " + data);
} finally {
ReferenceCountUtil.release(msg);
}
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
cause.printStackTrace();
ctx.close();
}
}
2、FixedLengthFrameDecoder(定长)
在Server类和Client类中initChannel方法中
//设置定长字符串接收
sc.pipeline().addLast(new FixedLengthFrameDecoder(5));
//设置字符串的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
Netty编解码技术
编解码技术就是java序列化技术,目的:第一进行网络传输,第二对象持久化
虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤太多,比如
java序列化没法跨语言、序列化后码流太大、序列化性能太低等等
主流框架:
JBoss的Marshalling包
goole的Protobuf
基于Protobuf的Kyro
MessagePack框架
JBoss的Marshalling是一个java对象序列化包,对JDK默认的序列化框架进行了优化,但又保持
跟java.io.Serializable接口的兼容,同时增加了一些可调的参数和附加特性
在Server类和Client类中initChannel方法中
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ReadTimeoutHandler(5));
sc.pipeline().addLast(new ServerHandler());
ServerHandler中
Req req = (Req) msg;
System.out.println("server:"+req.getId()+","+req.getName()+","+req.getRequestMessage());
Resp resp = new Resp();
resp.setId(req.getId());
resp.setName(req.getName());
resp.setResponseMessage(req.getRequestMessage());
ctx.writeAndFlush(resp);
MarshallingCodeCFactory类
public final class MarshallingCodeCFactory {
/**
* 创建Jboss Marshalling解码器MarshallingDecoder
* @return MarshallingDecoder
*/
public static MarshallingDecoder buildMarshallingDecoder() {
//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallerFactory和configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024);
return decoder;
}
/**
* 创建Jboss Marshalling编码器MarshallingEncoder
* @return MarshallingEncoder
*/
public static MarshallingEncoder buildMarshallingEncoder() {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
}
webSocket将网络套接字引入到了客户端和服务端,
ws特点:
单一的tcp连接,双方可通信
对代理、防火墙和路由器透明
无头部信息、Cookie和身份验证
无安全开销
通过ping\pong帧保持链路激活
服务器可主动传递给客户端,不在需要客户端轮询
实践
两台机器或者多台使用Netty进行通信
第一种,使用长连接通道不断开的形式进行通信,服务器和客户端通道一直处于开启状态
第二种,一次性批量提交数据,采用短连接方式
第三种,使用特殊的长连接,在指定的时间内,没有通信就断开,下次通信在建立连接
如何设置超时后关闭通道,关闭后又如何再次建立连接
5秒钟关闭,server和Client都要设置
sc.pipeline().addLast.(new ReadTimeoutHandler(5));
关闭之后,Client开启一个线程去建立连接
new Thread(new Runnable(){
public void run() {
try {
System.out.println("进入子线程");
ChannelFuture cf = c.getChannelFuture();//一个连接服务器方法
System.out.println(cf.channel().isActive());
System.out.println(cf.channel().isOpen());
//再次发送数据
Req request = new Req();
request.setId(""+4);
request.setName("pro"+4);
request.setRequestMessage("数据信息"+4);
cf.channel().writeAndFlush(request);
cf.channel().closeFuture().sync();
System.out.println("子线程结束");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
客户端宕机时关闭通道,下次客户端重启之后再次建立连接,服务器宕机重启后,如何建立连接
心跳检测
Netty实现文件服务器上传下载
相比Struts或springmvc,Netty上传下载支持大文件,异步,并发,性能好,非阻塞
fastdfs支持小文件上传,hdfs支持大文件、断点续传
介绍:是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,它提供了
简单易用的api从网络处理代码中解耦业务逻辑。Netty完全基于NIO实现的,Netty是异步的。
Netty健壮性、功能、性能、可定制性和可扩展性在同类框架都是首屈一指的。
网站:http://ifeve.com/netty5-user-guide/
Netty实现通信的步骤:
1:创建两个NIO线程组,一个用于网络事件处理(接受客户端的连接),另一个则进行网络
通信的读写。
2:创建一个ServerBootstarp对象,配置Netty的一系列参数,如传出去数据的缓存
3:创建一个实际处理数据的类ChannelInitializer,进行初始化的准备工作,比如设置接受传出
数据的字符集、格式、已经实际处理数据的接口
4:绑定端口,执行同步阻塞方法等待服务器端口启动即可
Netty对Byte实现了优化,因为有两个指针
TCP粘包、拆包问题
1、应用程序write写入的字节大小大于套接口发送缓冲区的大小
2、进行MSS大小的TCP分段
3、以太网帧的payload大于MTU进行IP分片
TCP粘包、拆包解决方案
1、消息定长
2、在包尾部增加特殊字符进行分割,例如回车
3、将消息分为消息头和消息体,在消息头中包含表示消息总总长度的字段,然后进行业务处理
Hetty解决粘包、拆包问题
1、分隔符 DelimiterBasedFrameDecoder
在Server类和Client类中initChannel方法中
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
//设置字符串形式的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
Server类
public class Server {
public static void main(String[] args) throws InterruptedException {
//第一个线程组 是用于接收Client端连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
//第二个线程组 适用于实际的业务处理操作的
EventLoopGroup workerGroup = new NioEventLoopGroup();
//创建一个辅助类Bootstrap,就是对我们Server进行一系列的配置
ServerBootstrap b = new ServerBootstrap(); // (2)
//把两个工作线程组加入进来
b.group(bossGroup, workerGroup)
//我要指定使用NioserverSocketChannel这种类型的通道
.channel(NioServerSocketChannel.class)
//一定要使用childHandler去绑定具体的事件处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// TODO Auto-generated method stub
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture f = b.bind(8765).sync();
f.channel().closeFuture().sync();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
ServerHandler类
public class ServerHandler extends ChannelHandlerAdapter{
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String request = (String)msg;
System.out.println("Server:"+request);
//写给客户端
String response = "我是反馈的信息$_";
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()))
.addListener(ChannelFutureListener.CLOSE);
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
cause.printStackTrace();
ctx.close();
}
}
Client类
public class Client {
public static void main(String[] args) throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>(){
@Override
protected void initChannel(SocketChannel sc) throws Exception {
// TODO Auto-generated method stub
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture cf1 = b.connect("127.0.0.1",8765).sync();
cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));
cf1.channel().writeAndFlush(Unpooled.wrappedBuffer("hello netty!$_".getBytes()));
cf1.channel().closeFuture().sync();
group.shutdownGracefully();
}
}
ClientHandler类
public class ClientHandler extends ChannelHandlerAdapter{
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
//do something msg
String data = (String)msg;
System.out.println("Client: " + data);
} finally {
ReferenceCountUtil.release(msg);
}
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// TODO Auto-generated method stub
cause.printStackTrace();
ctx.close();
}
}
2、FixedLengthFrameDecoder(定长)
在Server类和Client类中initChannel方法中
//设置定长字符串接收
sc.pipeline().addLast(new FixedLengthFrameDecoder(5));
//设置字符串的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
Netty编解码技术
编解码技术就是java序列化技术,目的:第一进行网络传输,第二对象持久化
虽然我们可以使用java进行对象序列化,netty去传输,但是java序列化的硬伤太多,比如
java序列化没法跨语言、序列化后码流太大、序列化性能太低等等
主流框架:
JBoss的Marshalling包
goole的Protobuf
基于Protobuf的Kyro
MessagePack框架
JBoss的Marshalling是一个java对象序列化包,对JDK默认的序列化框架进行了优化,但又保持
跟java.io.Serializable接口的兼容,同时增加了一些可调的参数和附加特性
在Server类和Client类中initChannel方法中
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
sc.pipeline().addLast(new ReadTimeoutHandler(5));
sc.pipeline().addLast(new ServerHandler());
ServerHandler中
Req req = (Req) msg;
System.out.println("server:"+req.getId()+","+req.getName()+","+req.getRequestMessage());
Resp resp = new Resp();
resp.setId(req.getId());
resp.setName(req.getName());
resp.setResponseMessage(req.getRequestMessage());
ctx.writeAndFlush(resp);
MarshallingCodeCFactory类
public final class MarshallingCodeCFactory {
/**
* 创建Jboss Marshalling解码器MarshallingDecoder
* @return MarshallingDecoder
*/
public static MarshallingDecoder buildMarshallingDecoder() {
//首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
//创建了MarshallingConfiguration对象,配置了版本号为5
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
//根据marshallerFactory和configuration创建provider
UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024);
return decoder;
}
/**
* 创建Jboss Marshalling编码器MarshallingEncoder
* @return MarshallingEncoder
*/
public static MarshallingEncoder buildMarshallingEncoder() {
final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");
final MarshallingConfiguration configuration = new MarshallingConfiguration();
configuration.setVersion(5);
MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);
//构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
MarshallingEncoder encoder = new MarshallingEncoder(provider);
return encoder;
}
}
webSocket将网络套接字引入到了客户端和服务端,
ws特点:
单一的tcp连接,双方可通信
对代理、防火墙和路由器透明
无头部信息、Cookie和身份验证
无安全开销
通过ping\pong帧保持链路激活
服务器可主动传递给客户端,不在需要客户端轮询
实践
两台机器或者多台使用Netty进行通信
第一种,使用长连接通道不断开的形式进行通信,服务器和客户端通道一直处于开启状态
第二种,一次性批量提交数据,采用短连接方式
第三种,使用特殊的长连接,在指定的时间内,没有通信就断开,下次通信在建立连接
如何设置超时后关闭通道,关闭后又如何再次建立连接
5秒钟关闭,server和Client都要设置
sc.pipeline().addLast.(new ReadTimeoutHandler(5));
关闭之后,Client开启一个线程去建立连接
new Thread(new Runnable(){
public void run() {
try {
System.out.println("进入子线程");
ChannelFuture cf = c.getChannelFuture();//一个连接服务器方法
System.out.println(cf.channel().isActive());
System.out.println(cf.channel().isOpen());
//再次发送数据
Req request = new Req();
request.setId(""+4);
request.setName("pro"+4);
request.setRequestMessage("数据信息"+4);
cf.channel().writeAndFlush(request);
cf.channel().closeFuture().sync();
System.out.println("子线程结束");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
客户端宕机时关闭通道,下次客户端重启之后再次建立连接,服务器宕机重启后,如何建立连接
心跳检测
Netty实现文件服务器上传下载
相比Struts或springmvc,Netty上传下载支持大文件,异步,并发,性能好,非阻塞
fastdfs支持小文件上传,hdfs支持大文件、断点续传