前言
本文主要是让大家简单的了解一下BIO和NIO的相应的一个区别,并编写了两个测试类,大家可以本地编码测试,更好的体会到两个的区别
一、什么是BIO、NIO
阻塞IO:简称BIO,linux中默认所有的socket都是blocking,其特点是进程会一直阻塞,直到数据拷贝完成。
非阻塞IO:简称NIO,其特点是进程会反复调用IO函数,并马上返回,但在数据拷贝的过程中,进行仍然是阻塞的。
二、测试类编写
1.BIO
代码如下(示例):
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class BioService {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9000);
while (true){
Socket accept = serverSocket.accept();
System.out.println("accept客户端开始连接");
new Thread(new Runnable() {
@Override
public void run() {
try{
handlerData(accept);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
}
private static void handlerData(Socket socket) throws IOException {
byte[] bytes = new byte[1024];
System.out.println("开始读取数据");
//接收客户端的数据,阻塞方法,没有数据可读时就阻塞线程
int read = socket.getInputStream().read(bytes);
System.out.println("read 读取数据完毕");
if (read!=-1){
System.out.println("接收到客户端发送的数据:" + new String(bytes,0,read));
}
}
}
2.NIO测试类
代码如下(示例):
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Niosocket {
//客户端连接保存队列
static List<SocketChannel> socketChannelsList = new ArrayList<>();
public static void main(String[] args) throws IOException {
//创建NIOServerSocketChannel与BIO的serverSocket类似
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//创建访问端口
serverSocketChannel.socket().bind(new InetSocketAddress(90000));
//设置serversocketChannel为非阻塞
serverSocketChannel.configureBlocking(false);
System.out.println("serverSocketChannel启动成功");
while (true) {
//非阻塞模式accept方法不会阻塞,其他的会阻塞
//NIO的非阻塞是由系统内部实现的,底层调用了linx内核的accept函数
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
System.out.println("客户端连接成功");
//设置socketChannel为非阻塞模型
socketChannel.configureBlocking(false);
//保存客户端放在集合中
socketChannelsList.add(socketChannel);
}
//遍历队列数据 注:必须用遍历器遍历,因为后续需要断开连接
Iterator<SocketChannel> iterator = socketChannelsList.iterator();
while (iterator.hasNext()) {
SocketChannel socket = iterator.next();
ByteBuffer allocate = ByteBuffer.allocate(128);
int readData = socket.read(allocate);
if (readData > 0) {
System.out.println("接收到客户端数据:" + new String(allocate.array()));
} else if (readData == -1) {
iterator.remove();
System.out.println("客户端断开连接");
}
}
}
}
}
2.多路复用IO测试类
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class NiosocketService {
//客户端连接保存队列
static List<SocketChannel> socketChannelsList = new ArrayList<>();
public static void main(String[] args) throws IOException {
//创建NIOServerSocketChannel与BIO的serverSocket类似
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//创建访问端口
serverSocketChannel.socket().bind(new InetSocketAddress(90000));
//设置serversocketChannel为非阻塞
serverSocketChannel.configureBlocking(false);
//打开Selector处理Channel,即创建epoil
Selector selector = Selector.open();
//把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("serverSocketChannel启动成功");
while (true) {
//阻塞等待需要处理的事件发生
selector.select();
//
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//获取selector中注册的全部事件的selectionKey实例
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()){
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
SocketChannel accept = channel.accept();
accept.configureBlocking(false);
SelectionKey register = accept.register(selector, SelectionKey.OP_READ);
System.out.println("客户端连接成功");
}else if (key.isReadable()){
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer allocate = ByteBuffer.allocate(128);
int read = channel.read(allocate);
//如果有数据则把他打印出来
if (read>0){
System.out.println("接收到客户端信息:" + new String(allocate.array()));
}else if (read==-1){//如果客户端断开连接,关闭socket连接
System.out.println("客户端断开连接");
channel.close();
}
}
iterator.remove();
}
}
}
}
2.本地调试步骤
1.电脑键盘window+R 呼出控制台
2.输入cmd 打开黑窗口
3.建立客户端连接,在黑窗口中输入telent localhost 9000
4.发送你要发送的信息,例如: send helloword
5.这时候你可以在代码控制台收到的信息 helloword
总结
以上就是今天要讲的内容,本文仅仅简单介绍了BIO和NIO的使用,如果大家有不理解的或者需要更改的大家可以私信或者评论