网络通信NIO selector demo

总体流程图

共分为4个步骤,读图顺序从步骤1读到步骤4

事件触发条件说明

ACCEPT:接收事件,当被轮询到Channel接受到新的连接时触发

READ:读事件,当被轮询到Channel的缓冲区有数据时触发

NIOServer

public class NIOServer {
    public static void main(String[] args) throws IOException {
        //创建selector
        Selector selector = Selector.open();
        //创建serverSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //通道设置为非阻塞
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        //通道注册到selector并监听accept事件,等待client连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            //此处会阻塞,直到有就绪事件(accept或read)
            selector.select();

            //得到所有就绪事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey key : selectionKeys) {
                //接收事件(有新的client连接进入)
                if (key.isAcceptable()){
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    //得到client的channel
                    SocketChannel socketChannel = channel.accept();
                    //通道设置为非阻塞,不设置无法注册到selector,会抛异常
                    socketChannel.configureBlocking(false);
                    //注册client的channel并监听读事件
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }
                else if (key.isReadable()){
                    try(SocketChannel socketChannel = (SocketChannel) key.channel();){
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                        //读出client传过来的数据
                        int len = socketChannel.read(byteBuffer);
                        if (len < 0){
                            continue;
                        }
                        byteBuffer.flip();
                        String msg = new String(byteBuffer.array(), 0, byteBuffer.remaining());
                        System.out.println(msg);

                        //响应client
                        socketChannel.write(ByteBuffer.wrap(("response:"+msg).getBytes(StandardCharsets.UTF_8)));
                        byteBuffer.clear();
                        System.out.println("---------睡眠1秒---------");
                        Thread.sleep(1000);
                    }
                    catch (IOException | InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
            //循环后需要手动清空,不然下次会被重复执行
            selectionKeys.clear();
        }
    }
}

Client

public class NIOClient {
    public static void main(String[] args) throws IOException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        //启动5个线程
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            executorService.execute(() -> {
                try (SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(8080));)
                {
                    //向server发送消息
                    socketChannel.write(ByteBuffer.wrap(("hello nio:"+ finalI).getBytes(StandardCharsets.UTF_8)));
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

                    //读取server的响应
                    socketChannel.read(byteBuffer);
                    byteBuffer.flip();
                    System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
                    byteBuffer.clear();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }

        executorService.shutdown();
    }
}

输出结果

server

hello nio:2
---------睡眠1秒---------
hello nio:3
---------睡眠1秒---------
hello nio:4
---------睡眠1秒---------
hello nio:1
---------睡眠1秒---------
hello nio:0
---------睡眠1秒---------

client

response:hello nio:2
response:hello nio:3
response:hello nio:4
response:hello nio:1
response:hello nio:0

总结

selector里面存放的内容可理解为是channel+事件的一个组合,当selector轮询到某个channel的事件被触发了,系统就会告知用户系统可开始对该channel进行IO操作了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值