关于在网络中使用BIO、NIO、AIO的示例
其他
2020-01-11 00:13:23
阅读次数: 0
关于在网络中使用BIO、NIO、AIO的示例
BIO 概述与示例
- 传统的单通道直连I/O,简单,但是阻塞成本高,主要阻塞点在:
- 建立连接:new Socket()、server.accept()
- 读:in.read()
- 写:out.write()
- 特征:不管Thread是否有空,都需要为每个Socket的连接、读、写操作进行等待
- BIO 服务端示例 (ServerDemo.java)
import com.skey.demo.util.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo {
public static void main(String[] args) {
ServerSocket server = null;
try {
server = new ServerSocket();
server.bind(new InetSocketAddress(23333));
while (true) {
Socket socket = server.accept();
new Thread(() -> handle(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(server);
}
}
private static void handle(Socket socket) {
InputStream in = null;
OutputStream out = null;
try {
in = socket.getInputStream();
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
System.out.println(new String(buffer));
}
out = socket.getOutputStream();
out.write("World".getBytes());
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(out, in);
}
}
}
- BIO 客户端示例 (ClientDemo.java)
import com.skey.demo.util.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientDemo {
public static void main(String[] args) {
Socket socket = null;
OutputStream out = null;
InputStream in = null;
try {
socket = new Socket("127.0.0.1", 23333);
out = socket.getOutputStream();
out.write("Hello".getBytes());
out.flush();
socket.shutdownOutput();
in = socket.getInputStream();
byte[] buffer = new byte[1024];
while (in.read(buffer) != -1) {
System.out.println(new String(buffer));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(in, out, socket);
}
}
}
NIO 概述与示例
- NIO即non-blocking IO 或者 new IO,是对于传统BIO几个阻塞点的优化,主要逻辑是:
- 通过Selector轮询管理channel的连接、读、写状态
- 再由其他线程根据channel的状态进行不同的处理
- 特征:单独的Thread管理Socket的连接、读、写状态,其他Thread根据状态进行处理
- NIO 服务端示例 (ServerDemo.java)
import com.skey.demo.util.IOUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class ServerDemo {
public static void main(String[] args) {
ServerSocketChannel ssc = null;
try {
ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(23333));
ssc.configureBlocking(false);
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Set<SelectionKey> keySet = selector.selectedKeys();
Iterator<SelectionKey> iter = keySet.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
handle(key);
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(ssc);
}
}
private static void handle(SelectionKey key) {
if (key.isAcceptable()) {
System.out.println("handle: key.isAcceptable()");
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
try {
SocketChannel channel = ssc.accept();
channel.configureBlocking(false);
channel.register(key.selector(), SelectionKey.OP_READ);
System.out.println("channel -> OP_READ");
} catch (IOException e) {
e.printStackTrace();
}
} else if (key.isReadable()) {
System.out.println("handle: key.isReadable()");
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
PoolEngine pool = PoolEngine.getInstance();
pool.execute(new ServerHandler(key));
}
}
}
- NIO 服务端数据处理类 (ServerHandler.java)
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
public class ServerHandler implements Runnable {
private SelectionKey key;
public ServerHandler(SelectionKey key) {
this.key = key;
}
@Override
public void run() {
try {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = channel.read(buffer)) > 0) {
buffer.flip();
System.out.println("msg = " + new String(buffer.array(), 0, len));
buffer.clear();
}
if (len == -1) {
channel.close();
System.out.println("channel -> close");
} else {
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- NIO 客户端示例 (ClientDemo.java)
import com.skey.demo.util.IOUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class ClientDemo {
public static void main(String[] args) {
InetSocketAddress address = new InetSocketAddress("127.0.0.1", 23333);
SocketChannel channel = null;
try {
channel = SocketChannel.open(address);
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("hello world".getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
channel.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(channel);
}
}
}
AIO 概述与示例
- AIO即异步IO,或叫做NIO2,通过系统底层进行优化,相对于NIO其关键点在于:
- 通过监听系统底层IO连接触发后续处理,不再使用Selector轮询
- Linux底层因为是epoll,操作和Selector相似,所以AIO在Linux系统上性能相差不大
- 特征:监控系统底层IO连接,再由Thread进行处理
- AIO 服务端示例 (ServerDemo.java)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
public class ServerDemo {
public static void main(String[] args) {
try {
AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withCachedThreadPool(
Executors.newCachedThreadPool(), 4
);
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(channelGroup);
server.bind(new InetSocketAddress(23333));
CountDownLatch latch = new CountDownLatch(100);
server.accept(
null,
new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(AsynchronousSocketChannel channel, Object attachment) {
server.accept(null, this);
handle(channel);
latch.countDown();
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void handle(AsynchronousSocketChannel channel) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(
buffer,
buffer,
new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
attachment.flip();
System.out.println(new String(attachment.array(), 0, result));
channel.write(ByteBuffer.wrap("Server: world".getBytes()));
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
}
);
}
}
- AIO 客户示例 (ClientDemo.java)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
public class ClientDemo {
public static void main(String[] args) {
AsynchronousSocketChannel channel;
try {
channel = AsynchronousSocketChannel.open();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.connect(
new InetSocketAddress("127.0.0.1", 23333),
buffer,
new CompletionHandler<Void, ByteBuffer>() {
@Override
public void completed(Void result, ByteBuffer attachment) {
System.out.println("----connection is successfully----");
try {
channel.write(ByteBuffer.wrap("Client: hello".getBytes())).get();
channel.read(attachment).get();
attachment.flip();
System.out.println(new String(attachment.array()));
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
}
);
Thread.sleep(10000);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
附:代码相关工具类
- IOUtils.java
public class IOUtils {
public static void close(AutoCloseable... closeables) {
for (AutoCloseable closeable : closeables) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
- PoolEngine.java
import java.util.concurrent.*;
public class PoolEngine {
private PoolEngine() {
}
public static PoolEngine getInstance() {
return Inner.instance;
}
private static class Inner {
private static final PoolEngine instance = new PoolEngine();
}
private static int corePoolSize = 4;
private static int maximumPoolSize = 8;
private static long keepAliveTime = 100;
private static int queueCapacity = 1024;
private ExecutorService pool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(queueCapacity),
new ThreadPoolExecutor.AbortPolicy());
public void execute(Runnable runnable) {
if (pool != null) {
pool.execute(runnable);
}
}
public <T> Future<T> submit(Callable<T> callable) {
if (pool != null) {
return pool.submit(callable);
} else {
return null;
}
}
public void shutdown() {
if (pool != null) {
pool.shutdown();
pool = null;
}
}
}
发布了128 篇原创文章 ·
获赞 45 ·
访问量 15万+
转载自blog.csdn.net/alionsss/article/details/103724561