netty,io与nio的区别,先上代码在分析:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.0.Final</version>
</dependency>
依赖引入
io与nio虽然目标不一样,但操作还是一样的:
接收请求服务类代码:
package com.kaige123.daomu.bootjsp.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class server {
private int port = 8081;
public void run() throws Exception {
//bossGroup 用来接收进来的连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
//workerGroup 用来处理已经被接收的连接
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//启动 NIO 服务的辅助启动类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new serverHandle());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// 服务器绑定端口
ChannelFuture f = b.bind(port).sync();
// 等待服务器 socket 关闭 。
f.channel().closeFuture().sync();
} finally {
// 出现异常终止
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
System.out.println("连接关闭等异常");
}
}
public static void main(String[] args) throws Exception {
new server().run();
}
}
服务器绑定端口,绑定收到请求后的处理者,有2个类注意:
bossGroup 与workerGroup ,一个是收到请求池,一个是已连接池。当客户端断开后,应该从这里面剔除
处理请求服务类代码:
package com.kaige123.daomu.bootjsp.netty;
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.*;
import java.util.Arrays;
public class serverHandle extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf result = (ByteBuf) msg;
byte[] result1 = new byte[result.readableBytes()];
// msg中存储的是ByteBuf类型的数据,把数据读取到byte[]中
result.readBytes(result1);
String resultStr = new String(result1);
// 释放资源,这行很关键
result.release();
FileOutputStream fileOutputStream = new FileOutputStream("D:\\Java_apiCopy.rar", true);
Savedisk(fileOutputStream, result1);
sendMsg(ctx);
}
// 写入本地磁盘
public void Savedisk(FileOutputStream fileOutputStream, byte[] bytes) throws IOException {
fileOutputStream.write(bytes, 0, bytes.length);
fileOutputStream.close();
}
// 向客户端发送消息
public void sendMsg(ChannelHandlerContext ctx) {
String response = "OK BYTES Client!";
// 发送的数据必须转换成ByteBuf字节数据数组,进行传输
ByteBuf encoded = ctx.alloc().buffer(response.length());
encoded.writeBytes(response.getBytes());
ctx.write(encoded);
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}
msg字节数据,readableBytes一口气读取到本次共传输的数据
客户端请求代码:
package com.kaige123.daomu.bootjsp.netty;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class client {
public void connect(String host, int port) throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new clientHandle());
}
});
// 连接发服务器地址
ChannelFuture f = b.connect(host, port).sync();
// 关闭连接
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
System.out.println("连接关闭等异常");
}
}
public static void main(String[] args) throws Exception {
client client = new client();
client.connect("127.0.0.1", 8081);
}
}
发送请求,并注册当连接后,自己的处理者
客户端处理代码:
package com.kaige123.daomu.bootjsp.netty;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.FileInputStream;
public class clientHandle extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("客户端收到处理");
ByteBuf result = (ByteBuf) msg;
byte[] result1 = new byte[result.readableBytes()];
result.readBytes(result1);
System.out.println("收到数据:" + result1 + "收到长度: " + result1.length);
result.release();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
// 连接成功后,向server发送消息
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\Java_api.rar");
byte[] bytes = new byte[1024 * 8];
int len = -1;
while ((len = fileInputStream.read(bytes)) != -1) {
ByteBuf encoded = ctx.alloc().buffer(len);
encoded.writeBytes(bytes, 0, len);
ctx.write(encoded);
ctx.flush();
}
}
}
io与nio
io的分析:一个客户端一个socket连接,获得in与out流,在建立的相互相互通信。
1:当有n人来时,一人一个服务就吃不住了。(这点不重要)
2:当双方连接上时,数据并不是要一直交互的,资源就一直耗着,等对方的信息,这段等待时间是无意义的
nio猜测,io有切实干过n个例题,nio仅是接触了netty,下面是猜测:
1:netty是一个池,客户来了养池中,客户请求抓服务去接待。pass,如果真是这样,那么我还不敢用。为什么?因为这样就不能保证请求者与服务器是同一个,这样将出现数据混乱的问题
1例子求证:
客户端分2次发出数据,第一次是给客户端贴上标签。第二次请求是看客户端再次请求时,netty是取出贴在客户端身上的标签,还是空标签。如果是取出标签,说明处理者与客户端始终是一个,如果是空,说明对象不是同一个
申请全局变量:String filename;
长度不为3,是第一次请求去贴上标签,并将标签打印出来。
长度为3,是第二次请求打印全局变量。如果是一对一,那么这个标签就会保持。如果抓新的来服务,标签就是null,查看打印:
开启2个客户端去请求,第一次贴标签,第二次打印标签。打印的标签与贴上的标签一致。说明什么?说明一开始去服务与过一段时间去服务的都是同一人同一对象。这样则没有问题,保证数据的一致性。否则我不敢用
区别在于:
阻塞与非阻塞,当在read或write时,在干其他的时间可以的。但会出现问题。如上,第一次请求出来,修改10秒。第二次就收不到了,客户端发完就死掉了。服务器休息完也没拿到第二次数据。也就是,这个过程,就连读连写,过程不能在做其他事情
nio非阻塞,不需要阻塞来接收保证消息是在持续传输。即使这个过程中,我去干其他时间,消息回头还是会传递回来,正常收到。
阻塞非阻塞:
阻塞io:我一直等你来信息,保证消息持续传输
非阻塞你:我不用守着你来消息,即使这会我中途去干其他时间浪费了时间,但最后我返回调用处后这个消息还会被处理得到。
这就是阻塞与非阻塞,其区别在于,传输过程中其形式不同,从netty切入到nio