IO通信之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<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> 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'
客户端连接成功!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值