当前位置: 首页 > news >正文

Linux C++ 利用 io_uring 技术批量读取 tun 文件描述符的数据。

以下是参考的实现代码,IO_URING 操作必须要进行按页大小对齐(仅在O_DIRECT直接I/O下),不能是非对称的,一般大多数操作系统页大小为:4KB。

批量读取、writev 批量简写。 

                    static constexpr int MTU = ITap::Mtu;

                    struct io_uring ring;
                    memset(&ring, 0, sizeof(ring));

                    struct iovec tun_write_iov_data[PPP_TUN_ENTRIES_PACKET_SIZE];
                    Byte packets[PPP_TUN_ENTRIES_PACKET_SIZE][MTU];

                    SsmtThreadLocalTls& tls = ssmt_tls_;
                    tls.tun_write_iov_data = tun_write_iov_data;

                    if (io_uring_queue_init(PPP_TUN_ENTRIES_PACKET_SIZE, &ring, 0) < 0) {
                        Dispose();
                        return false;
                    }

                    bool any = false;
                    for (int i = 0; i < PPP_TUN_ENTRIES_PACKET_SIZE; i++) {
                        struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
                        if (NULL == sqe) {
                            goto LABEL_exit;
                        }

                        io_uring_prep_read(sqe, tun_fd, packets[i], MTU, 0);
                        sqe->user_data = (__u64)&packets[i][0];
                    }

                    io_uring_submit(&ring);
                    while (!disposed_) {
                        struct io_uring_cqe* cqes[PPP_TUN_ENTRIES_PACKET_SIZE];
                        __u32 count = io_uring_peek_batch_cqe(&ring, cqes, PPP_TUN_ENTRIES_PACKET_SIZE);
                        if (count == 0) {
                            int err = io_uring_wait_cqe(&ring, &cqes[0]);
                            if (err == -EINTR) {
                                continue;
                            }
                            elif(err >= 0) {
                                count = 1;
                            }
                            else {
                                break;
                            }
                        }
                        
                        ssmt_tls_.tun_wirte_iov_size = 0;
                        for (__u32 i = 0; i < count; i++) {
                            struct io_uring_cqe* cqe = cqes[i];
                            assert(NULL != cqe);

                            Byte* packet = (Byte*)cqe->user_data;
                            if (int bytes_transferred = cqe->res; bytes_transferred > 0) {
                                PacketInputEventArgs e{ packet, bytes_transferred };
                                tls.tun_fd_ = tun_fd;
                                OnInput(e);
                            }

                            struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
                            assert(NULL != sqe);

                            io_uring_prep_read(sqe, tun_fd, packet, MTU, 0);
                            sqe->user_data = (__u64)packet;
                        
                            io_uring_cqe_seen(&ring, cqe);
                        }

                        tls.tun_fd_ = -1;
                        io_uring_submit(&ring);
                        
                        if (tls.tun_wirte_iov_size > 0) {
                            int err = writev(tun_fd, tun_write_iov_data, tls.tun_wirte_iov_size);
                            for (int i = 0; i < tls.tun_wirte_iov_size; i++) {
                                struct iovec& iov = tls.tun_write_iov_data[i];
                                Mfree(iov.iov_base);
                            }

                            tls.tun_wirte_iov_size = 0;
                            if (err < 0) {
                                break;
                            }
                        }
                    }

                LABEL_exit:
                    io_uring_queue_exit(&ring);
                    Dispose();
                    return any;

write 批量收集或超限写出:

        bool TapLinux::Output(const void* packet, int packet_size) noexcept {
            if (NULL == packet || packet_size < 1) {
                return false;
            }

            int disposed = disposed_.load();
            if (disposed != FALSE) {
                return false;
            }
            
            // https://man7.org/linux/man-pages/man2/write.2.html
            int tun = static_cast<int>(reinterpret_cast<std::intptr_t>(GetHandle()));
            if (Ssmt()) {
                SsmtThreadLocalTls& tls = ssmt_tls_;
                int fd = tls.tun_fd_;
                if (fd != -1) {
                    tun = fd;

#if defined(BOOST_ASIO_HAS_IO_URING)
                    void* packet_copy = Malloc(packet_size);
                    if (NULL == packet_copy) {
                        return false;
                    }

                    struct iovec& iov = tls.tun_write_iov_data[tls.tun_wirte_iov_size++];
                    memcpy(packet_copy, packet, packet_size);

                    iov.iov_base = packet_copy;
                    iov.iov_len = packet_size;

                    if (tls.tun_wirte_iov_size >= PPP_TUN_ENTRIES_PACKET_SIZE) {
                        int err = writev(fd, tls.tun_write_iov_data, tls.tun_wirte_iov_size);
                        for (int i = 0; i < tls.tun_wirte_iov_size; i++) {
                            struct iovec& iov = tls.tun_write_iov_data[i];
                            Mfree(iov.iov_base);
                        }

                        tls.tun_wirte_iov_size = 0;
                        if (err < 0) {
                            return false;
                        }
                    }
#endif
                }
            }

            ssize_t bytes_transferred = ::write(tun, (void*)packet, (size_t)packet_size);
            return bytes_transferred > -1;
        }

相关文章:

  • 基于大模型预测的慢性稳定性心绞痛全周期管理系统技术方案文档
  • Flink介绍——发展历史
  • 克魔ios开发助手查看苹果手机各个硬件组件使用历史记录和耗能历史记录
  • MySQL主从数据库搭建
  • sort排序
  • 使用Python进行数据挖掘时如何有效的数据脱敏?
  • 资源单元(RU)分配和映射
  • 【JavaScript】十一、DOM对象的获取和修改
  • 多输入多输出 | Matlab实现CPO-LSTM冠豪猪算法优化长短期记忆神经网络多输入多输出预测
  • 05-02-自考数据结构(20331)- 动态查找-知识点
  • 离线知识库文档问答用唤醒+VOSK离线听写+DS-V2-16B+离线合成轻松高效实现
  • Rocky Linux 9.5中完美迁移mysql5.6.17到mysql5.7.11
  • 20250330-傅里叶级数专题之离散时间傅里叶变换(4/6)
  • js 强引用 ​弱引用
  • leetcode 28 Find the Index of the First Occurrence in a String
  • uv vs pip 速度实测
  • ENSP学习day12
  • aws(学习笔记第三十七课) lambda调用rekognition(名人视频分析)
  • PHY——LAN8720A 寄存器读写 (二)
  • 前向扩散公式推导细节
  • 2016年两学一做教育网站/如何加入百度推广
  • 临海受欢迎营销型网站建设/按效果付费的网络推广方式
  • 工程造价信息期刊/免费seo培训
  • 深圳兼职做网站/电商培训机构推荐
  • 网站定制系统数据处理软件/杭州关键词优化服务
  • 猫代理/seo专员是做什么的