目录
-----重点
io面向于流,nio面向于缓冲区
Netty 用4 ,5不安全
Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性。
应用场景
1.分布式开源框架中dubbo、Zookeeper,RocketMQ底层rpc通讯使用就是netty。
2.游戏开发中,底层使用netty通讯。
Spring cloud底层使用http通讯
Netty4.0以下
同步-对管道获取值用单个线程
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>3.3.0.Final</version>
</dependency>
netty服务端
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//接受客户端发来的数据
class ServerHander extends SimpleChannelHandler {
//通道被关闭的时候会被触发
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelClosed(ctx, e);
System.out.println("========channelClosed===========");
}
//必须建立连接,关闭通道的时候才会触发
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("========channelDisconnected===========");
}
//接受出现的异常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
super.exceptionCaught(ctx, e);
System.out.println("========exceptionCaught===========");
}
//接受客户端数据
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
super.messageReceived(ctx, e);
System.out.println("========messageReceived===========");
System.out.println("服务器获取客户端发来的参数"+e.getMessage());
ctx.getChannel().write("你好啊,客户端返回的");
}
}
//netty 服务器端
public class NettyServer {
//浏览器http://127.0.0.1:8080/访问看控制台
public static void main(String[] args) {
//1创建服务对象
ServerBootstrap serverBootstrap = new ServerBootstrap();
//2创建两个线程池 第一个 监听端口号 nio监听
ExecutorService boos = Executors.newCachedThreadPool();
ExecutorService wook = Executors.newCachedThreadPool();
//3将线程池放入工程
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boos,wook));
//4设置管道工程
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
//设置管道
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
//传输数据时直接转为string类型
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
//设置事件监听类
pipeline.addLast("serverHander",new ServerHander());
return pipeline;
}
});
//绑定端口
serverBootstrap.bind(new InetSocketAddress(8080));
System.out.println("netty服务器端被启动==========");
// while (true){
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("每隔0.5打印");
// }
}
}
netty客户端
package com.netty;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class ClientHander extends SimpleChannelHandler {
//通道被关闭的时候会被触发
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelClosed(ctx, e);
System.out.println("========channelClosed===========");
}
//必须建立连接,关闭通道的时候才会触发
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("========channelDisconnected===========");
}
//接受出现的异常
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
super.exceptionCaught(ctx, e);
System.out.println("========exceptionCaught===========");
}
//接受客户端数据
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
super.messageReceived(ctx, e);
System.out.println("========messageReceived===========");
System.out.println("服务器向客户端回复的内容"+e.getMessage());
}
}
public class NettyClient {
public static void main(String[] args) {
//1创建服务对象
ClientBootstrap clientBootstrap = new ClientBootstrap();
//2创建两个线程池 第一个 监听端口号 nio监听
ExecutorService boos = Executors.newCachedThreadPool();
ExecutorService wook = Executors.newCachedThreadPool();
//3将线程池放入工程
clientBootstrap.setFactory(new NioClientSocketChannelFactory(boos,wook));
//4设置管道工程
clientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
//设置管道
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
//传输数据时直接转为string类型
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("encoder",new StringEncoder());
//设置事件监听类
pipeline.addLast("clientHander",new ClientHander());
return pipeline;
}
});
//绑定端口
ChannelFuture connect = clientBootstrap.connect(new InetSocketAddress("127.0.0.1", 8080));
System.out.println("netty客户端端被启动==========");
Channel channel = connect.getChannel();
Scanner scanner = new Scanner(System.in);
while (true){
System.out.println("输入内容=====");
channel.write(scanner.next());
}
}
}
Netty5.0(4.0及其以上粘包和拆包 分隔符区别)
官网上说netty不安全
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling</artifactId>
<version>1.3.19.GA</version>
</dependency>
<dependency>
<groupId>org.jboss.marshalling</groupId>
<artifactId>jboss-marshalling-serial</artifactId>
<version>1.3.19.GA</version>
<scope>test</scope>
</dependency>
NettyServer.java
package com.cn;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
class ServerHander extends ChannelHandlerAdapter{
/**
* 当通道被调用,执行方法(拿到数据) 127.0.0.1:8080测试
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String value=(String)msg;
System.out.println("服务器收到客户端msg:"+value);
//回复客户端
ctx.writeAndFlush("收到了。。。");
// ctx.write("111");
// ctx.write("666");
// ctx.flush();
}
}
public class NettyServer {
public static void main(String[] args) {
System.out.println("服务器端启动。。。。");
try {
//1创建两个线程池 一个负责接受客户端,一个进行传输
NioEventLoopGroup pGroup = new NioEventLoopGroup();
NioEventLoopGroup cGroup = new NioEventLoopGroup();
//2创建辅助类
ServerBootstrap b = new ServerBootstrap();
b.group(pGroup,cGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG,1024)
//3设置缓冲区大小
.option(ChannelOption.SO_SNDBUF,32*1024).option(ChannelOption.SO_RCVBUF,32*1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel sc) throws Exception {
//设置返回是string类型
sc.pipeline().addLast(new StringDecoder());//解码
sc.pipeline().addLast(new ServerHander());
}
});
//启动
ChannelFuture cf = b.bind(8080).sync();
//关闭
cf.channel().closeFuture().sync();
pGroup.shutdownGracefully();
cGroup.shutdownGracefully();
}catch (Exception e){
}
}
}
结果
服务器端启动。。。。
服务器收到客户端msg:ceh1ceh2ceh3
服务器收到客户端msg:ceh4ceh5ceh6
NettyClient.java
package com.cn;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
class ClientHander extends ChannelHandlerAdapter {
/**
* 当通道被调用,执行方法(拿到数据) 127.0.0.1:8080测试
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String value=(String)msg;
System.out.println("服务器收到客户端msg:"+value);
}
}
public class NettyClient {
public static void main(String[] args) {
System.out.println("客户端启动。。。。");
try {
//创建负责接受客户端连接
NioEventLoopGroup pGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(pGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel sc) throws Exception {
//设置返回是string类型
sc.pipeline().addLast(new StringDecoder());//解码
sc.pipeline().addLast(new ClientHander());
}
});
//启动
ChannelFuture cf = b.connect("127.0.0.1",8080).sync();
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
Thread.sleep(1000);
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("ceh1_dd".getBytes()));
//等待客户端端口号关闭
cf.channel().closeFuture().sync();
pGroup.shutdownGracefully();
}catch (Exception e){
}
}
}
粘包与拆包(TCP)
拆包方式一代码
ByteBuf byteBuf = Unpooled.copiedBuffer("_dd".getBytes());//有dd就发送
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));
拆包方式二(不常用)
sc.pipeline().addLast(new FixedLengthFrameDecoder(10));
服务器端和客户端都加上
序列化和反序列化
dobble用接口调用,底层用netty,通过netty通讯,将接口转化为二进制文件,传给服务器端
序列化协议(数据交换格式) :json,xml,protobuf