NIO

为什么要使用NIO创建NIO服务器端代码创建NIO客户端运行结果

为什么要使用NIO

jdk1.4之前的BIO是一种同步阻塞的通信模型,使用线程池虽然能达到提高性能,但是在一些高QPS请求下,仍然会存在线程阻塞的风险,NIO可以减少线程的使用的数量,核心技术点使用Linux的poll/epoll函数的调用,在BIO中处理连接请求时,需要单独的线程处理时,NIO只需要一个线程处理连接请求。NIO是JDK1.4引入的,NIO弥补了BIO的不足。

创建NIO服务器端代码

public class Server {

public static void main(String[] args) throws IOException {

// NIO是面向管道的

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress("127.0.0.1",10001));

serverSocketChannel.configureBlocking(false);

// 调用底层Selector

Selector selector = Selector.open();

// 将ServerSocketChannel注册到Selector上,并对请求连接的时间感兴趣,ServerSocketChannel只负责接受请求,所以一个线程就够了

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

// select是阻塞的,是一个逆向的操作,当socket的文件描述符准备就绪时,通知应用层程序

while (true){

// 此方法是阻塞方法

selectionKeys.select();

// 有事件发生,获取全部发生的事件集合

Set selectionKeys = selector.selectedKeys();

Iterator iterator = selectionKeys.iterator();

// 删除事件,防止重复执行事件

iterator.remove();

if (iterator.hasNext()){

SelectionKey next = iterator.next();

// 如果当前事件是一个请求连接的事件,正式由于nio提供了判断事件类型的机制,体现了nio是非阻塞

if (next.isAcceptable()){

ServerSocketChannel serverSocket = (ServerSocketChannel) next.channel();

// 获得请求连接请求的socket

ServerSocket socket = serverSocket.socket();

// 接受请求,并获取管道

SocketChannel acceptSocket = socket.accept().getChannel();

// 设置为非阻塞,必须设置,否则会报错

acceptSocket.configureBlocking(false);

// 将当前的socketChannel注册到selector中,并关注读事件(这里的读是相对于从socket缓冲区中读取事件)

acceptSocket.register(selector,SelectionKey.OP_READ);

System.out.println("客户端连接成功!");

} else if (next.isReadable()){

SocketChannel socketChannel = (SocketChannel) next.channel();

// nio是面向buffer,bio是面向stream

ByteBuffer byteBuffer = ByteBuffer.allocate(100);

int read = socketChannel.read(byteBuffer);

if (read > 0){

byteBuffer.flip();

byte[] bytes = new byte[byteBuffer.remaining()];

byteBuffer.get(bytes);

String string = new String(bytes, "UTF-8");

System.out.println("服务求收到消息:" + string);

}

}

}

}

}

}

创建NIO客户端

public class Client {

public static void main(String[] args) throws IOException {

Selector selector = Selector.open();

SocketChannel socketChannel = SocketChannel.open();

socketChannel.configureBlocking(false);

socketChannel.register(selector, SelectionKey.OP_CONNECT);

socketChannel.connect(new InetSocketAddress("127.0.0.1",10001));

System.in.read();

}

}

运行结果

Connected to the target VM, address: '127.0.0.1:50885', transport: 'socket'

客户端连接成功!

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: