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.LinkedList;
public class SocketNIO {
public static void main(String[] args) throws IOException, InterruptedException {
//selector = Selector.open(); 可以使用这个做多路复用器
LinkedList<SocketChannel> clients = new LinkedList<>();//存放曾今连接过的客户端
ServerSocketChannel ss = ServerSocketChannel.open();//开启监听
ss.bind(new InetSocketAddress(9090));
ss.configureBlocking(false);//该步骤能让服务端不用阻塞等待客户端的连接
while (true) {
//使当前线程休眠,进入阻塞状态
Thread.sleep(1000);
//接受客户端的连接
SocketChannel client = ss.accept();//在这里并不会阻塞,直接返回了客户端或者null
if (client != null) {
client.configureBlocking(false);//设置非阻塞模式。为之后的读取,recv设置非阻塞
int port = client.socket().getPort();
System.out.println("client-port:" + port);
clients.add(client);
}
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
for (SocketChannel socketChannel : clients) {
int num = socketChannel.read(buffer);
if (num > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes);
String str = new String(bytes);
System.out.println(socketChannel.socket().getPort() + ":" + str);
buffer.clear();
}
}
}
}
}
这个时候,内核提供了个select函数,它能够返回当前连接线程的状态,不需要自己轮询,直接调用select,能收到哪个线程的状态发生了变化,获取到后程序再自己recev那个线程。bio:同步阻塞,因为他有recev,accept。nio同步非阻塞,他返回的客户端没有阻塞。bio,nio属于同步io模型。aio:异步非阻塞,由内核通知主程序带一个buffer过去。自己拉数据叫同步,需要自己recv。被内核推过来数据叫异步。
BIO需要来一个连接就开启一个线程等待接收数据处理。NIO轮询内核,等待内核告诉服务端哪个连接有数据需要处理(返回的是状态,由程序根据状态自己去recv数据)。