JAVA NIO简单入门例子

服务端代码

package com.nio.test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServerApplication {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        Selector selector = Selector.open();

        //绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        //设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        //注册serverSocketChannel到selector,并关注OP_ACCEPT
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("服务端启动成功!");

        while (true) {
            //没有事件发生
            if (selector.select(1000) == 0) {
                continue;
            }
            //有事件发生,找到发生事件的Channel对应的SelectionKey合集
            Set<SelectionKey> selectorKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectorKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();

                // 发生 OP_ACCEPT 事件,处理连接请求
                if (selectionKey.isAcceptable()) {
                    System.out.println("收到连接请求");
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 将 socketChannel 也注册到 selector,关注 OP_READ事件,并给 socketChannel 关联 Buffer
                    socketChannel.register(selector, SelectionKey.OP_READ, new ReadWriteBuffer());
                }

                // 发生 OP_READ 事件,读客户端数据
                if (selectionKey.isReadable()) {
                    System.out.println("读取就绪");
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    //取出建立连接时添加的缓存
                    ReadWriteBuffer readWriteBuffer = (ReadWriteBuffer) selectionKey.attachment();
                    //读取数据
                    ByteBuffer readBuffer = readWriteBuffer.readBuffer;
                    int read;
                    StringBuilder stringBuilder = new StringBuilder();
                    while ((read = channel.read(readBuffer)) > 0) {
                        readBuffer.flip();
                        byte[] readByte = new byte[read];
                        readBuffer.get(readByte);
                        stringBuilder.append(new String(readByte));
                        readBuffer.clear();
                    }

                    System.out.println("msg form client:" + stringBuilder);
                    // 添加写事件
                    selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
                    // 回复客户端
                    String result = "服务端收到消息了!";
                    readWriteBuffer.writeBuffer.put(result.getBytes());
                    //读取不到数据就把channel关闭
                    if(read == -1) {
                        channel.close();
                    }
                }

                if (selectionKey.isWritable() && selectionKey.isValid()) {
                    System.out.println("写入就绪");
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    //取出buffer进行读取
                    ReadWriteBuffer readWriteBuffer = (ReadWriteBuffer) selectionKey.attachment();
                    readWriteBuffer.writeBuffer.flip();
                    if(readWriteBuffer.writeBuffer.hasRemaining()) {
                        channel.write(readWriteBuffer.writeBuffer);
                    } else {
                        // 注销写事件
                        selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
                    }
                    // 将buffer中没有用到的数据进行迁移
                    readWriteBuffer.writeBuffer.compact();
                }

                // 手动从集合中移除当前的 selectionKey,防止重复处理事件
                iterator.remove();
            }
        }
    }

    static class ReadWriteBuffer {
        //处理读操作
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        //处理写操作
        ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
    }
}

客户端代码

package com.nio.test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class NioClientApplication {

    public static void main(String[] args) throws IOException {
        //单线程池
        ExecutorService single = Executors.newSingleThreadExecutor();
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

        Selector selector = Selector.open();
        SocketChannel socketChannel = SocketChannel.open();
        Scanner scanner = new Scanner(System.in);
        socketChannel.configureBlocking(false);
        //与服务端建立连接
        socketChannel.connect(new InetSocketAddress("localhost", 8080));
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
        while (true) {
            if (selector.select(1000) == 0) {
                continue;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();
                //处理连接事件
                if (selectionKey.isConnectable()) {
                    if (socketChannel.finishConnect()) {
                        socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
                    }
                }
                //处理读事件
                if (selectionKey.isReadable()) {
                    readBuffer.clear();
                    int read = socketChannel.read(readBuffer);
                    byte[] readByte = new byte[read];
                    readBuffer.flip();
                    readBuffer.get(readByte);
                    System.out.println("读取到数据:" + new String(readByte));
                    //重新注册写事件
                    selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
                }
                //处理写事件
                if (selectionKey.isWritable()) {
                    //使用线程写数据到服务端
                    threadWrite(single, writeBuffer, socketChannel, scanner);
                    //取消注册写事件(不取消会造成上一次数据可能还没发送,下次进来还会继续执行
                    selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
                }
            }
            iterator.remove();
        }
    }

    static void threadWrite(ExecutorService single, ByteBuffer writeBuffer, SocketChannel socketChannel, Scanner scanner) {
        single.execute(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "请输入:");
                String line = scanner.nextLine();
                writeBuffer.put(line.getBytes());
                writeBuffer.flip();
                //写入数据
                while (writeBuffer.hasRemaining()) {
                    socketChannel.write(writeBuffer);
                }
                writeBuffer.compact();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

操作步骤:先启动服务端NioServerApplication,在启动客户端NioClientApplication。

就是一个入门的简单例子。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值