前言
在Java中,提供了一些关于使用IO的API,可以供开发者来读写外部数据和文件,我们称这些API为Java IO。IO是Java中比较重要知识点,且比较难学习的知识点。并且随着Java的发展为提供更好的数据传输性能,目前有三种IO共存;分别是BIO、NIO和AIO。
同步阻塞I/O模式
是一个比较传统的通信方式,模式简单,使用方便。但并发处理能力低,通信耗时,依赖网速。
同步非阻塞模式
NIO 与原来的 I/O 有同样的作用和目的, 他们之间最重要的区别是数据打包和传输的方式。原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。
异步非阻塞I/O模型
是一种非阻塞异步的通信模式。在NIO的基础上引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。
aio
目录结构如下图
新建客服端启动类 AioClient
java
public class AioClient {
public static void main(String[] args) throws Exception {
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
Future<Void> future = socketChannel.connect(new InetSocketAddress("192.168.108.89", 7397));
System.out.println("com.lm.netty01.aio client start done. {码农明哥 | 欢迎关注&获取源码}");
future.get();
socketChannel.read(ByteBuffer.allocate(1024), null, new AioClientHandler(socketChannel, Charset.forName("GBK")));
Thread.sleep(100000);
}
}
客户端消息处理器类
java
public class AioClientHandler extends ChannelAdapter {
public AioClientHandler(AsynchronousSocketChannel channel, Charset charset) {
super(channel, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
try {
System.out.println("程序员码农 | 链接报告信息:" + ctx.channel().getRemoteAddress());
//通知客户端链接建立成功
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelInactive(ChannelHandler ctx) {
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println("码农明哥 | 服务端收到:" + new Date() + " " + msg + "\r\n");
ctx.writeAndFlush("客户端信息处理Success!\r\n");
}
}
服务端
java
public class AioServer extends Thread {
private AsynchronousServerSocketChannel serverSocketChannel;
@Override
public void run() {
try {
serverSocketChannel = AsynchronousServerSocketChannel.open(AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10));
serverSocketChannel.bind(new InetSocketAddress(7397));
System.out.println("com.lm.netty01 aio server start done. 欢迎关注&获取源码}");
// 等待
CountDownLatch latch = new CountDownLatch(1);
serverSocketChannel.accept(this, new AioServerChannelInitializer());
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
public AsynchronousServerSocketChannel serverSocketChannel() {
return serverSocketChannel;
}
public static void main(String[] args) {
new AioServer().start();
}
}
初始化
java
public class AioServerChannelInitializer extends ChannelInitializer {
@Override
protected void initChannel(AsynchronousSocketChannel channel) throws Exception {
channel.read(ByteBuffer.allocate(1024), 10, TimeUnit.SECONDS, null, new AioServerHandler(channel, Charset.forName("GBK")));
}
}
处理消息
java
public class AioServerHandler extends ChannelAdapter {
public AioServerHandler(AsynchronousSocketChannel channel, Charset charset) {
super(channel, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
try {
System.out.println("码农明哥| 链接报告信息:" + ctx.channel().getRemoteAddress());
//通知客户端链接建立成功
ctx.writeAndFlush("码农明哥 | 通知服务端链接建立成功" + " " + new Date() + " " + ctx.channel().getRemoteAddress() + "\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelInactive(ChannelHandler ctx) {
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println("码农明哥 | 服务端收到:" + new Date() + " " + msg + "\r\n");
ctx.writeAndFlush("服务端信息处理Success!\r\n");
}
}
Channle适配器模仿Netty
java
public abstract class ChannelAdapter implements CompletionHandler<Integer, Object> {
private AsynchronousSocketChannel channel;
private Charset charset;
public ChannelAdapter(AsynchronousSocketChannel channel, Charset charset) {
this.channel = channel;
this.charset = charset;
if (channel.isOpen()) {
channelActive(new ChannelHandler(channel, charset));
}
}
@Override
public void completed(Integer result, Object attachment) {
try {
final ByteBuffer buffer = ByteBuffer.allocate(1024);
final long timeout = 60 * 60L;
channel.read(buffer, timeout, TimeUnit.SECONDS, null, new CompletionHandler<Integer, Object>() {
@Override
public void completed(Integer result, Object attachment) {
if (result == -1) {
try {
channelInactive(new ChannelHandler(channel, charset));
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
buffer.flip();
channelRead(new ChannelHandler(channel, charset), charset.decode(buffer));
buffer.clear();
channel.read(buffer, timeout, TimeUnit.SECONDS, null, this);
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.getStackTrace();
}
public abstract void channelActive(ChannelHandler ctx);
public abstract void channelInactive(ChannelHandler ctx);
// 读取消息抽象类
public abstract void channelRead(ChannelHandler ctx, Object msg);
}
服务端测试
启动服务端
BIO
目录结构如下
客户端
java
public class BioClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("192.168.2.178", 7397);
System.out.println("itstack-demo-netty bio client start done. {关注公众号:bugstack虫洞栈 | 欢迎关注&获取源码}");
BioClientHandler bioClientHandler = new BioClientHandler(socket, Charset.forName("utf-8"));
bioClientHandler.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
消息处理器
java
public class BioClientHandler extends ChannelAdapter {
public BioClientHandler(Socket socket, Charset charset) {
super(socket, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
System.out.println("链接报告LocalAddress:" + ctx.socket().getLocalAddress());
ctx.writeAndFlush("hi! 我是码农明哥 BioClient to msg for you \r\n");
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
ctx.writeAndFlush("hi 我已经收到你的消息Success!\r\n");
}
}
服务端
java
public class BioServer extends Thread {
private ServerSocket serverSocket = null;
public static void main(String[] args) {
BioServer bioServer = new BioServer();
bioServer.start();
}
@Override
public void run() {
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(7397));
System.out.println("com.lm.netty01.bio bio server start done. {关注码农明哥| 欢迎关注&获取源码}");
while (true) {
Socket socket = serverSocket.accept();
BioServerHandler handler = new BioServerHandler(socket, Charset.forName("GBK"));
handler.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
消息处理器
java
public class BioServerHandler extends ChannelAdapter {
public BioServerHandler(Socket socket, Charset charset) {
super(socket, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
System.out.println("链接报告LocalAddress:" + ctx.socket().getLocalAddress());
ctx.writeAndFlush("hi! 我是码农明哥 BioServer to msg for you \r\n");
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
ctx.writeAndFlush("hi 我已经收到你的消息Success!\r\n");
}
}
适配器
java
public abstract class ChannelAdapter extends Thread {
private Socket socket;
private ChannelHandler channelHandler;
private Charset charset;
public ChannelAdapter(Socket socket, Charset charset) {
this.socket = socket;
this.charset = charset;
while (!socket.isConnected()) {
break;
}
channelHandler = new ChannelHandler(this.socket, charset);
channelActive(channelHandler);
}
@Override
public void run() {
try {
BufferedReader input = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), charset));
String str = null;
while ((str = input.readLine()) != null) {
channelRead(channelHandler, str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 链接通知抽象类
public abstract void channelActive(ChannelHandler ctx);
// 读取消息抽象类
public abstract void channelRead(ChannelHandler ctx, Object msg);
}
BIO测试
启动服务端
NIO
目录结构如下
客户端
java
public class NioClient {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
boolean isConnect = socketChannel.connect(new InetSocketAddress("192.168.2.178", 7397));
if (isConnect) {
socketChannel.register(selector, SelectionKey.OP_READ);
} else {
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}
System.out.println("com.lm.netty01.nio nio client start done. {关注码农明哥 | 欢迎关注&获取源码}");
new NioClientHandler(selector, Charset.forName("GBK")).start();
}
}
消息处理器
java
public class NioClientHandler extends ChannelAdapter {
public NioClientHandler(Selector selector, Charset charset) {
super(selector, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
try {
System.out.println("链接报告LocalAddress:" + ctx.channel().getLocalAddress());
ctx.writeAndFlush("hi! 我是,码农明哥 NioClient to msg for you \r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
ctx.writeAndFlush("hi 我已经收到你的消息Success!\r\n");
}
}
服务端
java
public class NioServer {
private Selector selector;
private ServerSocketChannel socketChannel;
public static void main(String[] args) throws IOException {
new NioServer().bind(7893);
}
public void bind(int port) {
try {
selector = Selector.open();
socketChannel = ServerSocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.socket().bind(new InetSocketAddress(port), 1024);
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("com.lm.netty01.nio server start done. {关注码农明哥 | 欢迎关注&获取源码}");
new NioServerHandler(selector, Charset.forName("GBK")).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
消息处理器
java
public class NioServerHandler extends ChannelAdapter {
public NioServerHandler(Selector selector, Charset charset) {
super(selector, charset);
}
@Override
public void channelActive(ChannelHandler ctx) {
try {
System.out.println("链接报告LocalAddress:" + ctx.channel().getLocalAddress());
ctx.writeAndFlush("hi! 我是码农明哥 NioServer to msg for you \r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandler ctx, Object msg) {
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
ctx.writeAndFlush("hi 我已经收到你的消息Success!\r\n");
}
}
Nio测试
启动NioServer
好了到这里就结束了基础的netty学习,大家一定要跟着动手操作起来。需要的源码的 可私信我获取;
重要:
给大家构建了个资源群 欢迎圈友携朋友一起加入 大家需要的si我进。