NIO 全称 Non Blocking IO , 也就是非阻塞IO,这里的阻塞体现在两个方面,
对于Java 来讲,nio 指的是new io,也就是说java.nio包里的类,可以是阻塞的,也可以是非阻塞的。
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
public class SocketNIONonBlocking {
public static void main(String[] args) throws Exception {
LinkedList clients = new LinkedList<>();
ServerSocketChannel ss = ServerSocketChannel.open();
ss.bind(new InetSocketAddress(9090));
ss.configureBlocking(false); //重点
while (true) {
Thread.sleep(2000);//为了方便日志分析,避免过多的系统调用
SocketChannel client = ss.accept(); //不会阻塞
if (client == null) {
System.out.println("client is null");
} else {
client.configureBlocking(false); //重点
int port = client.socket().getPort();
System.out.println("client port: " + port);
clients.add(client);
}
ByteBuffer buffer = ByteBuffer.allocateDirect(4096); //可以在堆里 堆外
for (SocketChannel c : clients) {
int num = c.read(buffer);
if (num > 0) {
buffer.flip();
byte[] aaa = new byte[buffer.limit()];
buffer.get(aaa);
String b = new String(aaa);
System.out.println(c.socket().getPort() + " : " + b);
buffer.clear();
}
}
}
}
}
$ strace -ff -o out java SocketNIONonBlocking
client is null
client is null
client is null
client is null
client is null
......
$ grep 'client is null' out.*
......
out.5136:write(1, "client is null", 14) = 14
out.5136:write(1, "client is null", 14) = 14
out.5136:write(1, "client is null", 14) = 14
out.5136:write(1, "client is null", 14) = 14
......
accept(4, 0x7f37300eae10, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
accept(4, 0x7f37300eae10, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
accept(4, 0x7f37300eae10, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
accept(4, 0x7f37300eae10, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1
accept(4, {sa_family=AF_INET6, sin6_port=htons(58014), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, [28]) = 5
......
fcntl(5, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0
.....
write(1, "client port: 58014", 19) = 19
write(1, "\n", 1) = 1
read(5, 0x7f6dd7c03cb0, 4096) = -1 EAGAIN (Resource temporarily unavailable)
accept(4, 0x7f6e100f8680, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
$ nc localhost 9090
abcdefg
grep abcdefg out.*
......
accept(4, 0x7fefc40dae40, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
mprotect(0x7fefc40e9000, 4096, PROT_READ|PROT_WRITE) = 0
read(5, "abcdefg\n", 4096) = 8
write(1, "59968 : abcdefg\n", 16) = 16
write(1, "\n", 1) = 1
futex(0x7fefc400be78, FUTEX_WAIT_PRIVATE, 0, {tv_sec=1, tv_nsec=999997296}) = -1 ETIMEDOUT (Connection timed out)
futex(0x7fefc400be28, FUTEX_WAKE_PRIVATE, 1) = 0
accept(4, 0x7fefc40dae40, [28]) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "client is null", 14) = 14
write(1, "\n", 1) = 1
.......
ss.configureBlocking(true);
client.configureBlocking(true);
向示例代码中的 configureBlocking方法传入true,这里就变成了阻塞IO,大家可以自行验证。