首页 > 其他分享 >7.NIO-selector-写入内容过多

7.NIO-selector-写入内容过多

时间:2022-10-12 13:35:06浏览次数:53  
标签:NIO iterator buffer 写入 selector write key sc

1.4.3、写入内容过多

服务端

public class WriteServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);

        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        ssc.bind(new InetSocketAddress(50001));

        while (true) {
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();

                if (key.isAcceptable()) {
                    SocketChannel sc = ssc.accept();
                    sc.configureBlocking(false);

                    StringBuilder builder = new StringBuilder();
                    for (int i = 0; i < 30000000; i++) {
                        builder.append("a");
                    }
                    ByteBuffer buffer = Charset.defaultCharset().encode(builder.toString());

                    while (buffer.hasRemaining()) {
                        int write = sc.write(buffer);//实际写入的字节数
                        System.out.println(write);
                    }
                }
            }
        }
    }
}

客户端

public class WriteClient {
    public static void main(String[] args) throws IOException {
        SocketChannel sc = SocketChannel.open();
        sc.connect(new InetSocketAddress(50001));

        int count = 0;
        while (true) {
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
            int read = sc.read(buffer);
            count += read;
            System.out.println(count);
            buffer.clear();
        }

    }
}

结果

# 服务端 中间好多0,就是buffer满了
.....
0
0
0
2621420
1703923
4310084
# 客户端
....
30000000

这样显然不合适,解决

  • 非阻塞模式下,无法保证把 buffer 中所有数据都写入 channel,因此需要追踪 write 方法的返回值(代表实际写入字节数)
  • 用 selector 监听所有 channel 的可写事件,每个 channel 都需要一个 key 来跟踪 buffer,但这样又会导致占用内存过多,就有两阶段策略
    • 当消息处理器第一次写入消息时,才将 channel 注册到 selector 上
    • selector 检查 channel 上的可写事件,如果所有的数据写完了,就取消 channel 的注册
    • 如果不取消,会每次可写均会触发 write 事件
private static void write2() throws IOException {
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.configureBlocking(false);

    Selector selector = Selector.open();
    ssc.register(selector, SelectionKey.OP_ACCEPT);
    ssc.bind(new InetSocketAddress(50001));

    while (true) {
        selector.select();
        Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
        while (iterator.hasNext()) {
            SelectionKey key = iterator.next();
            iterator.remove();

            if (key.isAcceptable()) {
                SocketChannel sc = ssc.accept();
                sc.configureBlocking(false);

                SelectionKey scKey = sc.register(selector, SelectionKey.OP_READ);
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < 30000000; i++) {
                    builder.append("a");
                }
                ByteBuffer buffer = Charset.defaultCharset().encode(builder.toString());

                int write = sc.write(buffer);//实际写入的字节数
                System.out.println(write);
                if (buffer.hasRemaining()) {
                    //关注可写事件。把之前已有事件加上,防止覆盖
                    scKey.interestOps(scKey.interestOps() + SelectionKey.OP_WRITE);
                    //把未写完数据挂到sckey上
                    scKey.attach(buffer);
                }
            } else if (key.isWritable()) {
                ByteBuffer buffer = (ByteBuffer) key.attachment();
                SocketChannel sc = (SocketChannel) key.channel();
                int write = sc.write(buffer);
                System.out.println(write);
                if (!buffer.hasRemaining()) {
                    key.attach(null);//清除附件
                    key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);//去掉事件
                }

            }
        }
    }
}

标签:NIO,iterator,buffer,写入,selector,write,key,sc
From: https://www.cnblogs.com/jpymll/p/16784224.html

相关文章

  • 1.1.NIO-三大组件
    1、NIO基础non-blockingio非阻塞io1.1、三大组件1.1.1、Channel&Bufferchannel类似于stream,它就是读写数据的双向通道,可以从channel将数据读入buffer,也可以将buffer......
  • #打卡不停更#在开鸿智谷NiobeU4移植lvgl并实现ADC按键状态显示
    本文主要分享在开鸿智谷NiobeU4开发板移植lvgl经验,并实现按键按下sw4显示SW4Pressed松开显示SW4Release,整理踩坑经验分享如下。1.移植准备开鸿智谷NiobeU4开发板Openhar......
  • 文件写入和追加
    内容刷新直接调用write,内容并未真正写入文件,而是会积攒在程序的内存中,称之为缓冲区当调用flush的时候,内容会真正写入文件这样做是避免频繁的操作硬盘,导致效率下降(攒一......
  • Netty学习之NIO基础
    Netty学习之NIO基础本博客是根据黑马程序员Netty实战学习时所做的笔记可先参考博客JavaNIO一、三大组件简介Channel与BufferJavaNIO系统的核心在于:通道(Channel)和......
  • 跨集群distcp数据的时候报错异常java.nio.channels.UnresolvedAddressException
    异常2022-10-1019:41:55,541INFO[IPCServerhandler17on33142]org.apache.hadoop.mapred.TaskAttemptListenerImpl:Diagnosticsreportfromattempt_166391297354......
  • 嵌套Json写入DataTable
    *json中的value的type有时候是个array,DataTable是不能写入这样的json的。但是由于业务需求有时候可能需要将json中的Array也写入DataTable。*解决方案是将DataTable中......
  • python如何调用openpyxl库把数据写入Excel?
    代码importosfromopenpyxlimportload_workbookproject_path=os.path.abspath(os.path.join(os.getcwd(),"../../../"))#获取项目路径根据实际改变#*====......
  • [Recoil] Intermediate Selectors
     interface:exporttypeElementStyle={position:{top:number;left:number}size:{width:number;height:number}}exporttypeElement={style:......
  • k8s 部署minio
    k8s部署minio部署NFSmkdir/nfs_data/minio_datachmod-R777/nfs_data/minio_data创建命名空间miniokubectlcreatensminioDeploymentapiVersion:apps/v1k......
  • C/C++ union联合体介绍
    C/C++union联合体介绍文章参考:https://blog.csdn.net/mooneve/article/details/92703036目录C/C++union联合体介绍1.联合体union简介2.联合体union内存分配与所占空......