【C/C++】从网卡到 socket:一个 DPDK 用户态协议栈的整体架构

Seastar C++20 异步框架实战:基于 DPDK 构建单核 30 万 QPS HTTP 服务器 本文详细介绍了如何使用Seastar C++20异步框架结合DPDK技术构建高性能HTTP服务器,实现单核30万QPS的惊人性能。通过无共享架构、用户态网络栈等创新设计,Seastar显著超越传统服务器性能,并提供从环境配置到代码实现的完整实战指南,助力开发者掌握现代高性能服务器开发技术。 阅读详情

【C/C++】从网卡到 socket:一个 DPDK 用户态协议栈的整体架构

一块网卡持续吐出报文时,I/O 线程不能停下来等某条 TCP 连接推进状态;应用调用 recv() 时,也不关心 PMD 正在哪一轮轮询。awesome-stack 需要协调的,正是这几种不同的节奏:网卡按批次收发,协议线程按连接维护状态,应用则按 socket 和 epoll 语义工作。

沿着一条报文的路径看,串起这些动作的是两级队列和一组真实的 Linux fd。I/O lcore 与协议 lcore 通过全局 ring 交换 mbuf,协议线程再借助每个 socket 的 ring、TCP 缓冲和 eventfd,把结果交给应用。需要内核处理的报文和路由变化,则分别经过 KNI 与 Netlink。相比按应用层、协议层、物理层逐层罗列模块,这条路径更接近代码实际运行的方式。

运行环境与启动形态

项目 README 给出的基础环境是 Ubuntu 16.04 和 DPDK 19.08.2,构建沿用 DPDK 19.08 legacy make。构建产物有三类:build/awesome-stack 可以独立运行,build/libawesome_stack.so 向修改过源码的应用提供 n* API,build/libawesome_stack_hook.so 则通过 LD_PRELOAD 接管现有应用的标准 socket 调用。

Ubuntu 16.04
DPDK 19.08.2
legacy make
├── build/awesome-stack
├── build/libawesome_stack.so
└── build/libawesome_stack_hook.so

无论从哪个入口启动,数据面至少需要三个 EAL lcore。main lcore 完成 EAL、端口、共享 mbuf pool、KNI 和全局 ring 的初始化,然后选出两个 worker:一个运行 packet_processing_thread,另一个运行 io_thread。独立程序可以通过 build/awesome-stack -l 1-3 -n 4 启动;以 hook 方式运行 Redis、Nginx、QUIC 或 iperf3 时,第一次创建 AF_INET TCP/UDP socket 会触发 awesome_stack_start_from_string()。两种方式最终进入同一套数据面。

unsigned int packet_lcore = rte_get_next_lcore(rte_lcore_id(), 1, 0);
unsigned int io_lcore = rte_get_next_lcore(packet_lcore, 1, 0);

g_inout_ring->in = rte_ring_create(
    "in_ring", 1024, rte_socket_id(),
    RING_F_SP_ENQ | RING_F_SC_DEQ);
g_inout_ring->out = rte_ring_create(
    "out_ring", 1024, rte_socket_id(), RING_F_SC_DEQ);

rte_eal_remote_launch(packet_processing_thread, g_mbuf_pool, packet_lcore);
rte_eal_remote_launch(io_thread, NULL, io_lcore);

main lcore 发起两个 worker 后,留在初始化与等待位置。至此,物理网卡 queue 0、两条全局 ring 和两个 worker 连成了最短的数据面闭环。

launch

launch

rte_eth_rx_burst

enqueue mbuf

dequeue mbuf

enqueue mbuf

dequeue mbuf

rte_eth_tx_burst

独立程序启动
或 hook 首次接管 socket

EAL main lcore
初始化并等待

I/O worker lcore
io_thread

协议 worker lcore
packet_processing_thread

物理网卡 queue 0

全局 in ring

全局 out ring

整体架构及 lcore 分工

io_thread 每轮只处理几项搬运工作:从网卡 queue 0 批量 RX,将 mbuf 放入 g_inout_ring->in;再从 g_inout_ring->out 取出待发送的 mbuf,批量 TX。它不查 TCP 状态,也不替应用寻找 socket。协议 worker 从全局入方向 ring 取包,交给 process_packet();完成收包处理后,还会轮询各 socket 的发送请求,并处理 KNI 请求。

全局 ring 负责两个 worker 之间的交接,应用侧还要按端点区分数据。因此,每个 socket_block_t 都有 in、out 两个 rte_ring,并保存地址、端口、协议、TCP 状态和缓冲。网卡侧传递的是 mbuf,越过 socket 边界时,传递的已是应用可以消费的对象或字节。

typedef struct socket_block {
    fd_object_t fd_object;
    struct rte_ring *in;
    struct rte_ring *out;

    uint32_t src_ip;
    uint16_t src_port;
    uint32_t dst_ip;
    uint16_t dst_port;
    int protocol;

    tcp_status_t tcp_status;
    uint32_t seq_una;
    uint32_t seq_nxt;
    uint32_t rcv_nxt;
    uint16_t snd_wnd;
    uint16_t rcv_wnd;

    uint8_t recv_buffer[MAX_TCP_WINDOW];
    segment_queue_t segment_queue;
    /* keepalive、persist、cwnd、ssthresh 等字段略 */
} socket_block_t;

UDP 收包时,携带地址和 payload 的 udp_offload_t 会进入 socket 的 in ring,由 nrecvfrom() 出队;nsendto() 创建的发送请求进入 out ring,等待协议线程组包。TCP 的对象路径不同:发送侧使用 tcp_offload_t,收到的 payload 写入 recv_buffer,监听 socket 的已完成连接通知使用 in ring,发送请求使用 out ring,尚未确认的报文段则留在 segment_queue 中。这些对象各走各的路径,因此不能把所有 TCP 数据都理解成经过 socket in ring。

NIC

I/O worker
批量 RX/TX

global in ring
RX mbuf

协议 worker
分派、状态机、组包

socket in ring
UDP 数据报 / accept 通知

TCP recv_buffer
字节流

socket_block
端点与连接状态

应用线程
recv / recvfrom / accept

socket out ring
UDP/TCP 发送请求

segment_queue
TCP 未确认段

global out ring
TX mbuf

两级队列把共享状态收束在明确的位置。I/O lcore 持续搬运,应用线程不直接持有 mbuf,TCP 的状态、窗口和定时器由协议 lcore 推进。跨线程交接集中在几次 enqueue/dequeue 上,一条数据停在哪里,也就有了清楚的排查落点。

收包路径与协议分派

报文进入物理端口后,io_thread 用 rte_eth_rx_burst() 批量取回 mbuf,再调用 burst enqueue,把它们交给全局 in ring。ring 容量不足时,未能入队的尾部 mbuf 会当场释放。协议线程批量出队后,逐个调用 process_packet(),网卡轮询与协议分支因此不会挤在同一个循环里。

uint16_t nb_rx = rte_eth_rx_burst(gport_id, 0, rx, BURST_SIZE);
uint32_t nb_enqueued = rte_ring_sp_enqueue_burst(
    g_inout_ring->in, (void **)rx, nb_rx, NULL);
for (uint32_t i = nb_enqueued; i < nb_rx; i++) {
    rte_pktmbuf_free(rx[i]);
}

/* packet_processing_thread */
uint16_t count = rte_ring_mc_dequeue_burst(
    g_inout_ring->in, (void **)rx, BURST_SIZE, NULL);
for (uint16_t i = 0; i < count; i++) {
    process_packet(rx[i], mbuf_pool);
}

process_packet() 先检查 EtherType。ARP 报文进入 ARP 处理,协议栈也会从 ARP 以及收到的 TCP/UDP 以太网源地址中,学习 IP 到 MAC 的动态映射;非 IPv4 报文则释放。对于 IPv4,代码会结合目的地址和运行模式判断归属:应用模式下,用户态 socket 没有消费的报文可以交给 KNI;路由模式下,本机报文交给 KNI,非本机报文进入 FIB 查找。只有归用户态协议栈处理的 TCP/UDP,才会继续进入对应的四层函数。

ARP

非 IPv4

IPv4

用户态 socket 消费

交给 Linux

路由模式非本机

UDP

TCP

其他

RX mbuf

EtherType

学习邻居 / 回应请求

释放 mbuf

目的地址与运行模式

next_proto_id

rte_kni_tx_burst

rte_lpm 最长前缀匹配

process_udp_packet

process_tcp_packet

选择并查询 ARP 下一跳

global out ring

UDP 找到匹配的 socket_block_t 后,会构造 udp_offload_t,并放入该 socket 的 in ring。只有数据成功入队,代码才会唤醒阻塞的接收者并报告 EPOLLIN;应用从等待中返回时,队列里已经有对象可取。

socket_block_t *local = find_localhost_by_ip_port(
    ip_hdr->dst_addr, udp_hdr->dst_port, IPPROTO_UDP,
    ip_hdr->src_addr, udp_hdr->src_port);

if (rte_ring_mp_enqueue(local->in, udp_offload) < 0) {
    rte_free(udp_offload);
} else {
    pthread_cond_signal(&local->cond);
    notify_socket_readable(local->fd_object.fd);
    if (ep != NULL)
        nepoll_event_callback(ep, local->fd_object.fd, EPOLLIN);
}

TCP 收包还涉及连接查找和状态推进。process_tcp_packet() 校验 checksum 后,先以四元组从 DPDK hash 查找已连接 socket;没有命中时,再匹配 LISTEN socket。接下来,当前 tcp_status 决定报文进入 tcp_listen_handle()、tcp_syn_received_handle()、tcp_established_handle() 等处理函数中的哪一个。

listen

connect / SYN

收到 SYN / 回 SYN+ACK

收到 SYN+ACK / 回 ACK

收到 ACK / 通知 accept

收到 FIN

主动 close / 发 FIN

FIN 被确认

同时关闭

收到 FIN

应用 close

FIN 被确认

FIN 被确认

2MSL 到期

CLOSED

LISTEN

SYN_SENT

SYN_RECEIVED

ESTABLISHED

CLOSE_WAIT

FIN_WAIT_1

FIN_WAIT_2

CLOSING

TIME_WAIT

LAST_ACK

连接进入 ESTABLISHED 后,payload 写入 recv_buffer,rcv_nxt 和接收窗口随之更新,之后才唤醒 recv() 与 epoll。ACK 到来时,协议线程释放已经确认的 segment,推进 seq_una,重启最早未确认段的重传计时,并按慢启动或拥塞避免更新 cwnd。重传、persist、keepalive、延迟 ACK 和快速恢复也都留在这条按连接推进的路径中,没有压到 I/O lcore 上。

socket、fd 与 epoll 的应用接口

报文进入 socket 状态后,还要以应用熟悉的方式交付出去。核心库提供 nsocket()、nbind()、naccept()、nsend()、nrecv() 等接口;hook 动态库拦截同名标准函数,只将 AF_INET 的 TCP/UDP socket 交给用户态协议栈。普通文件描述符、Unix socket 和其他 fd 继续走 libc,因此同一个进程可以同时持有内核对象和协议栈对象。

int socket(int domain, int type, int protocol)
{
    LOAD_LIBC(socket);
    int base_type = type & 0xf;
    if (!hook_enabled() || stack_starting() || domain != AF_INET ||
        (base_type != SOCK_STREAM && base_type != SOCK_DGRAM)) {
        return libc_socket(domain, type, protocol);
    }
    if (ensure_stack_started() < 0)
        return -1;
    return nsocket(domain, type, protocol);
}

ssize_t recv(int fd, void *buf, size_t len, int flags)
{
    if (is_stack_fd(fd))
        return nrecv(fd, buf, len, flags);
    LOAD_LIBC(recv);
    return libc_recv(fd, buf, len, flags);
}

nsocket() 返回的同样是真实 Linux fd。get_next_fd() 创建一个 eventfd,将它放入 fd_table,再由 socket_block_t 或 eventpoll 持有。应用原有的 fd 范围检查与内核等待机制因而仍有可用对象;协议栈产生可读数据时,只需向这个 eventfd 写入计数,便能唤醒等待路径。

int get_next_fd(fd_object_t *block)
{
    int fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (fd < 0 || fd >= FD_TABLE_SIZE)
        return -1;

    block->fd = fd;
    fd_table[fd] = block;
    return fd;
}

void notify_socket_readable(int fd)
{
    uint64_t value = 1;
    (void)write(fd, &value, sizeof(value));
}

协议栈内部的 epoll 用红黑树保存注册项,用 ready list 保存已经就绪的项。UDP 数据报入队、TCP payload 写入缓冲或监听连接完成后,协议线程调用 nepoll_event_callback(),将对应的 epitem 放进 ready list,并通过条件变量和 eventfd 唤醒等待者。

混合 epoll 还增加了一层配对。hook 同时维护内核 epoll fd 与协议栈 epoll fd,并把后者的 eventfd 注册进内核 epoll。epoll_wait() 先在内核侧等待,读到 stack marker 后,再以 timeout=0 取用户态 ready list,最后把两边的事件一并交回应用。应用原来的事件循环因此无须预先判断一个 fd 属于哪一侧。

应用线程 kernel epoll stack epoll socket_block 协议 worker 应用线程 kernel epoll stack epoll socket_block 协议 worker 数据入队或写 recv_buffer eventfd write nepoll_event_callback(EPOLLIN) stack epoll fd 变为可读 libc epoll_wait 返回 marker nepoll_wait(timeout=0) 合并用户态与内核事件 recv / recvfrom / accept

这组接口把协议线程里的状态变化转换成了应用认识的可读事件。真实 eventfd 也为 fcntl、ioctl(FIONBIO) 和混合 epoll 提供了衔接点。不过,当前源码重点实现和接管的是 epoll,不能据此推断 poll、select 已经完整实现。

发包、KNI 与路由模式如何合流

再沿反方向看应用发送。send() 交给协议栈的是一段字节;nsend() 先提交 socket 的 TCP 发送请求,协议线程再结合 snd_wnd、cwnd、MSS 和未确认数据切分 segment,补上序号与 ACK。nsendto() 则构造 udp_offload_t,放进 socket out ring。等 Ethernet、IPv4 和 TCP/UDP 头与 checksum 全部填好,发送对象才成为 mbuf,进入全局 out ring。

/* 应用线程:提交 UDP 发送请求 */
if (rte_ring_mp_enqueue(socket_block->out, udp_offload) < 0) {
    rte_free(udp_offload);
    return -1;
}

/* 协议线程:组包后提交给 I/O lcore */
if (rte_ring_mp_enqueue(g_inout_ring->out, send_mbuf) < 0) {
    rte_pktmbuf_free(send_mbuf);
    return -1;
}

/* I/O lcore:批量发到物理端口 */
pending_tx = rte_ring_sc_dequeue_burst(
    g_inout_ring->out, (void **)tx, BURST_SIZE, NULL);
uint16_t sent = rte_eth_tx_burst(gport_id, 0, tx, pending_tx);

协议线程完成组包后,I/O lcore 从全局 out ring 批量取出 mbuf,再调用 rte_eth_tx_burst() 发往物理端口。应用提交、协议组包和网卡发送依然处在三种不同的执行节奏中,彼此只通过 socket out ring 和全局 out ring 两次交接。

KNI 是一条双向兼容通道。数据面决定交给 Linux 的报文,通过 rte_kni_tx_burst() 送入内核的 vEth0;Linux 从 vEth0 发出的包,则由 I/O lcore 调用 rte_kni_rx_burst() 取回,再直接经 rte_eth_tx_burst() 发往物理网卡。这里的 tx 和 rx 都是从 KNI 一侧命名的,理解方向时需要跟着报文走,不能只凭函数名判断。

路由模式把另一类 IPv4 报文接入同一个出口。route_sync_start() 通过 NETLINK_ROUTE 读取 Linux 主路由表,先获取现有路由,再订阅后续变化。只有目标接口上的 IPv4 单播、非 multipath 路由会写入 rte_lpm,默认接口名为 vEth0。FIB 最多保存 4096 条规则,此外还有独立的默认路由槽。

非本机 IPv4 报文完成最长前缀匹配后,直连路由以目的 IP 为下一跳,带 gateway 的路由则使用 gateway。ARP 表提供下一跳 MAC;TTL 小于等于 1 的报文直接丢弃,其余报文递减 TTL、更新 IPv4 checksum、改写 Ethernet MAC,然后进入全局 out ring。

NETLINK_ROUTE

add/delete

是

否

是

否

FRR / ip route

Linux 主路由表

route_sync thread

DPDK rte_lpm FIB

非本机 IPv4 mbuf

route_fib_lookup

gateway 是否为 0

下一跳 = 目的 IP

下一跳 = gateway

ARP 表查 MAC

TTL <= 1

丢弃

TTL - 1
更新 IPv4 checksum
改写 Ethernet

global out ring

I/O lcore

物理网卡

这样一来,KNI 为本机流量和用户态未处理的报文保留内核去向,Netlink 把 Linux 已有的路由控制面结果同步给 DPDK FIB,协议线程负责实际的转发查表。KNI 没有成为主数据快路径,Linux 也没有退出系统;两者分别留在兼容面和控制面。

设计取舍、收益与边界

沿着整条链路回看,几个关键选择的作用与代价都很具体。I/O 和协议处理分属两个 worker lcore,网卡轮询无须等待 TCP 状态分支、ARP 查询和定时处理,代价是 mbuf 要跨全局 ring 交接。全局 ring 只搬运 RX/TX mbuf,per-socket ring 和 TCP 缓冲保留端点语义,应用线程与协议轮询因而可以独立推进。与此同时,socket_block_t 较重,TCP 还有固定 64 KiB 收发缓冲;连接规模上升时,内存与管理成本需要重新评估。

真实 eventfd 加 hook,让 Redis、Nginx 这类现有应用可以继续使用常见的 socket 与 epoll 调用,普通 fd 和 Unix socket 仍交给 libc。这种兼容依赖 hook 对 API 语义的覆盖。当前实现接住了常用 socket、epoll、fcntl 与 ioctl(FIONBIO) 等路径,但不能等同于 Linux socket 的全部行为。KNI 与 Netlink 复用 Linux 的兼容面和路由控制面,也意味着运行时仍要关注 KNI 生命周期、vEth0 配置与 Linux 路由表。

RX mbuf

UDP 对象 / TCP 字节 / accept 通知

eventfd + epoll

send / sendto

发送请求

TX mbuf

未由用户态消费 / 本机流量

Netlink

NIC

I/O lcore

global in ring

协议 lcore

per-socket 状态

应用

global out ring

KNI ↔ Linux

Linux 路由表

rte_lpm

README 还记录了一次 Redis benchmark:用户态栈为 20833.33 requests/s,内核栈为 15723.27 requests/s。这只是 README 中特定环境的一次结果,可以作为该环境下的运行记录,不能外推为用户态栈普遍快于 Linux 内核协议栈。

测试覆盖也限定了结论的边界。仓库现有单元测试主要涉及 epoll close、hook ioctl 和 Netlink 解码,尚不足以证明完整数据面的正确性;完整 TCP 状态机、丢包重传、并发连接与端到端收发,仍需要更系统的回归与压力测试。因此,这套实现适合用来观察网卡轮询、协议状态和应用接口如何闭合,但不能据此宣称生产可用、RFC 完整兼容、端到端零拷贝、全链路无锁或在所有场景胜过内核栈。

从收包方向看,RX mbuf 由 NIC 经过 I/O lcore 和全局 in ring 到达协议 lcore,TCP/UDP 状态再借助 per-socket 队列、缓冲与 eventfd,转化为应用可见的事件。发送方向沿 socket out ring 和全局 out ring 回到 NIC。KNI 为需要 Linux 的报文保留去向,Netlink 为转发路径提供路由结果。

学习链接: https://github.com/0voice

C++高频交易系统设计:十大实战技巧与性能优化指南 在追求极致性能的金融交易领域,系统延迟的确定性是核心诉求。其原理在于对硬件资源与软件行为的全栈精确控制,以消除垃圾回收、动态内存分配等引入的非确定性开销。这带来了极高的技术价值:在纳秒级竞争中,稳定的低延迟直接决定了策略的盈利能力。应用场景广泛覆盖算法交易、做市商系统和量化对冲基金。本文聚焦C++在高频交易中的工程实践,深入剖析如何通过内存池、无锁数据结构、用户态网络协议栈(如DPDK)和缓存友好设计等关键技术,构建高性能、高可靠的核心交易系统,并自然融入事件驱动架构、性能剖析等热词,为开发者提供从理论到落 阅读详情

相关推荐

C++高频交易系统低延迟优化:从内核旁路到无锁数据结构实战

在追求极致性能的金融科技领域,低延迟是系统设计的核心目标。其原理在于通过软硬件协同优化,最大限度地减少数据处理各环节的耗时,从而在微秒甚至纳秒级别的竞争中占据先机。这项技术的核心价值在于为高频交易、实时风控等场景提供稳定且可预测的极速响应能力,是量化策略能否盈利的关键基础设施。应用场景广泛覆盖证券、期货、数字货币等市场的自动化交易。要实现纳秒级延迟,需深入系统底层,其中内核旁路技术(如DPDK)能绕过操作系统协议栈,直接从网卡获取数据,大幅降低网络I/O开销;同时,无锁数据结构利用原子操作替代传统锁机制,彻

weixin_30268071的博客 638

Seastar C++20 异步框架实战:基于 DPDK 构建 10Gbps 网络服务,延迟降低 90%

本文详细介绍了如何利用Seastar C++20异步框架和DPDK构建高性能网络服务,实现10Gbps吞吐量并将延迟降低90%。通过环境配置、深度集成、核心架构设计及性能优化等实战步骤,展示了Seastar在多核服务器应用程序中的卓越表现,为开发者提供了完整的高性能网络解决方案。

weixin_33690963的博客 399

NXP QorIQ SDK v2.0-1703深度解析:DPDK与ODP赋能高性能网络处理器开发

在嵌入式网络设备开发中,软件定义网络(SDN)和网络功能虚拟化(NFV)对数据平面处理性能提出了更高要求。其核心原理在于通过用户态数据包处理框架,绕过操作系统内核协议栈,直接访问硬件加速资源,从而大幅降低延迟、提升吞吐量。这一技术价值在于能将芯片的纸面算力转化为实际产品的核心竞争力,广泛应用于路由器、交换机、安全网关和边缘计算节点等场景。本文聚焦于NXP QorIQ处理器平台,深入剖析其最新SDK如何通过深度集成DPDK和ODP两大框架,并结合DPAA2硬件加速架构,为开发者提供了一套完整的高性能网络应用开

dfuw13072的博客 457

Linux C/C++ 学习日记(47):dpdk(八):UDP的pps测试:内核 VS dpdk

摘要:本文对比了DPDK和标准POSIX API在UDP发包性能上的差异。测试结果显示,DPDK发包速率达17.8万PPS,是标准Socket(7.2万PPS)的2.4倍。性能差异主要源于:1)DPDK绕过内核协议栈,消除上下文切换开销;2)采用零拷贝技术,避免用户态-内核态内存拷贝;3)支持批量发包优化;4)使用轮询替代中断模式。特别在小包场景下,DPDK优势更显著,因其性能不受内核交互开销影响。测试代码实现了两种发包方式,验证了DPDK在高吞吐网络应用中的明显优势。

2302_79943247的博客 916

C++校招简历实战项目精选:从HTTP服务器到游戏引擎的硬核技能提升

C++作为高性能系统编程的核心语言,其价值在于对计算机底层原理的深刻理解和工程实践能力。从内存管理、多线程并发到网络通信,掌握这些基础概念是构建复杂系统的前提。理解事件驱动模型、协议解析等原理,能够帮助开发者设计出高性能的后端服务。在技术价值层面,通过实现具体项目,可以将理论知识转化为解决实际问题的能力,例如构建高并发服务器或音视频处理工具。这些技能在后端开发、音视频处理、游戏引擎和嵌入式系统等应用场景中至关重要。本文精选了覆盖多个热门方向的C++实战项目,如基于Epoll的高性能HTTP服务器和简易RPC

cuanji3287的博客 749

Android12 车载开发TaskView实现分屏

这里只给出TaskView的代码,相关联的源码,请看源码,如果想要使用TaskView需要自己去编译frameWork的源码,打包一个aar,或者jar出来使用,否则无法直接使用。1.如果分屏的应用如启动两个应用按照权重占比,互相不叠加在一起,点触摸击事件都可响应,例如左边启动QQ了,右边启动的是微信,二者窗口都可操作。TaskView是谷歌整合安卓多任务多窗口下交互重新重构的独立出来的module,本身继承自ServiceView,TaskView的相关概念性的东西参考。//创建的taskview。

android_bird_bird的博客 9550

DPDK与零拷贝技术:构建微秒级延迟的C++交易系统网络核心

在追求极致性能的分布式系统和高并发服务中,网络I/O延迟和吞吐量是核心瓶颈。传统基于内核协议栈的通信模型,由于系统调用、上下文切换和内存拷贝等开销,难以满足对延迟和吞吐有严苛要求的场景。DPDK(数据平面开发套件)通过用户态轮询和内核旁路技术,从根本上消除了这些开销,实现了网络数据包从网卡到应用层的直接路径。结合零拷贝技术,进一步避免了数据在用户空间和内核空间之间的冗余复制,极大降低了CPU负载和内存带宽占用。这两项技术的工程价值在于,它们能够将网络处理延迟稳定降低至微秒甚至纳秒级,同时将吞吐量推至硬件极限

weixin_33749242的博客 355

Pyinstaller 打包 Pyzbar 时缺失 DLL 文件的排查与修复指南

本文详细解析了使用Pyinstaller打包Pyzbar库时,因缺失关键DLL文件导致程序闪退的常见问题。文章提供了从问题复现、错误诊断到最终修复的完整解决方案,核心在于通过修改.spec配置文件,手动将缺失的libzbar-64.dll等文件添加到打包过程中,确保生成的可执行文件能独立运行。

wdx012345的博客 504

【C++系统软件突破性进展】:2025大会披露的协议栈优化黑科技

突破低时延网络性能瓶颈,2025 全球 C++ 及系统软件技术大会:低时延 C++ 网络协议栈的实现揭秘高效协议栈设计。聚焦高频交易、实时通信场景,采用零拷贝、内核旁路与对象池技术,显著降低处理延迟。核心优化方法全公开,值得收藏。

InstrIsle的博客 907

YOLOv5+Astra Pro Plus深度相机:手把手教你实现实时目标检测(附ROS配置技巧)

本文详细介绍了如何将YOLOv5目标检测算法与Astra Pro Plus深度相机结合,构建实时目标检测系统。内容涵盖从硬件选型、环境搭建、ROS配置到YOLOv5部署与深度信息融合的完整流程,并分享了性能优化、避障算法等实战技巧,帮助开发者在机器人视觉等场景中快速实现智能感知应用。

weixin_28292761的博客 387

Autosar结合simulink的汽车应用层软件开发实例

本文基于汽车应用开发案例,并结合Autosar相关知识,生成具有Autosar标准的汽车应用层开发代码,以供学习和参考。以上就是本篇内容,主要是利用Simulink创建Autosar接口并进行端口映射的方法。

m0_64899535的博客 2152

【C/C++】手写 DPDK 协议栈(五):用 mbuf 实现 UDP 的 bind、recvfrom 与 sendto

课程实现清楚展示了用户态 UDP 的最小路径,但生产实现还应补上:UDP 长度与 mbuf 边界校验、队列满时的回压策略、IPv4 选项/分片处理、套接字并发保护,以及按 NUMA/lcore 分片的 socket 表。UDP 阶段把协议解析、逻辑 socket、ring 和条件变量串起来:RX 线程负责快,应用线程负责业务。关键点是 socket 层不持有原始 mbuf:协议线程解析后复制应用需要的元数据与负载,随后释放 mbuf。先填字段,将 IP 校验和、UDP 校验和清零,再分别调用。

wycgi的博客 224

问题:dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)

 1. 问题:Ubuntu安装软件的过程中出现依赖项的问题 “E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).” 按照指示执行如下两条命令都没有解决问题。 sudo apt-get -f install sudo apt-get --fix-broken ...

gloria_littlechi的博客 2万+

【2025全球C++技术大会精华】:低时延网络协议栈设计的7大核心原则

掌握低时延网络设计核心方法,解决高并发场景性能瓶颈。本文基于2025全球C++及系统软件技术大会:低时延C++网络协议栈的实现,提炼7大设计原则,涵盖零拷贝、无锁队列、内核旁路等关键技术,适用于金融交易、实时通信等系统。架构优化与性能提升兼备,值得收藏。

LiteTrans的博客 1066

工业自动化实战:用LabVIEW的DSC模块实现MODBUS-TCP设备控制

本文详细介绍了如何利用LabVIEW的DSC模块实现工业自动化中的MODBUS-TCP设备控制。通过环境准备、核心功能解析、状态机实现及典型工业场景实战,帮助工程师快速掌握稳定可靠的通讯技术,提升工业自动化系统的运行效率。

salt9的博客 1057

车载软件刷写工具vFlash --- 自动化接口(Automation API)应用简介

车载软件刷写工具vFlash --- 自动化接口(Automation API)应用简介

Soly_kun的博客 361

c++ kernel bypass技术 c++如何实现内核旁路网络栈

绕开的是 socket、recv()、send() 这套机制,不是绕开内核本身——驱动仍需内核加载,DMA 地址映射、MMIO 寄存器访问也依赖内核支持。强行用 extern "C" 包一层 rte_eth_dev_configure() 没问题,但若在类构造函数里调 rte_eal_init(),就容易踩到静态初始化顺序陷阱——DPDK 要求 rte_eal_init() 必须是进程里第一个被调用的 DPDK 函数,且不能在任何全局对象构造中触发。不适合 Web 后端或带复杂 TLS/HTTP 的服务。

NotFound486的博客 235

【51单片机仿真】基于51单片机设计的温湿度采集检测系统__资料编号11

该系统通过与AT89C51单片机、LCD1602显示屏和DHT11温湿度传感器的集成,实时读取环境中的温度和湿度数据并在LCD1602上显示这些信息,其中系统初始化LCD1602显示屏、通过DHT11_receive()函数接收并校验DHT11传感器的温湿度数据、使用LCD_ShowNum()函数逐位显示湿度和温度数据并在这些数据后附加相应的单位符号,以便用户可以直观地看到当前环境的温湿度情况。

嵌入式阿齐Archie 2万+

高性能C++网络转发引擎设计:如何实现微秒级数据包处理?

掌握微秒级数据包处理核心技术,提升数据中心性能。在2025全球C++及系统软件技术大会:数据中心网络C++转发引擎设计中,深入解析高性能C++转发引擎的架构设计、零拷贝与多线程优化方法,适用于高吞吐低延迟场景,显著降低处理延迟,值得收藏。

CodeNexus的博客 783

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【系统级编程巅峰之作】:2025年C++转发引擎设计必须掌握的7个性能调优点

掌握高性能C++转发引擎设计核心方法,解决数据中心网络低延迟高吞吐难题。聚焦2025全球C++及系统软件技术大会:数据中心网络C++转发引擎设计,详解零拷贝、无锁队列、SIMD优化等7大关键技术,适用于高速报文处理场景,显著提升系统效率,值得收藏。

InitPulse的博客 1030

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

C/C++高频交易系统ODIN V3.1:架构设计与性能优化实战

在追求极致性能的金融科技领域,低延迟交易系统是量化交易的核心竞争力。其基本原理在于通过精细控制硬件资源、优化数据处理流程,将行情接收、策略运算到订单发送的全链路延迟压缩至微秒甚至纳秒级,从而在高速市场中捕捉转瞬即逝的交易机会。这类系统的技术价值在于将计算机体系结构、操作系统与网络编程知识深度融合,实现性能的极限压榨。其典型应用场景包括高频做市、套利以及需要自主可控核心交易系统的量化基金。本文以ODIN V3.1项目为例,深入剖析了如何运用C/C++语言特性,结合共享内存、无锁队列等并发编程技术,以及自定义内

weixin_34187862的博客 369

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

1024程序员节特献:C++高频交易系统设计十大技巧(专家级实战经验)

1024程序员节特献C++高频交易系统开发技巧,深入解析低延迟、高并发场景下的系统设计十大核心方法。涵盖内存池优化、无锁队列、CPU亲和性等关键技术,显著提升交易性能与稳定性,专家级实战经验值得收藏。

CodeVibe的博客 1002

C++构建千公里AI算力调度系统:挑战、技术与架构实战

分布式计算是现代大规模AI训练与高性能计算的核心基础,其核心原理在于通过网络将多台计算机的算力与存储资源进行整合,以解决单一节点无法处理的复杂问题。在AI算力调度领域,这一技术价值尤为凸显,它能够将分散在不同地域的异构计算设备(如GPU、TPU)高效协同,支撑起千亿参数大模型的训练任务。面对跨地域、长距离带来的网络延迟、带宽成本与异构资源管理等系统级难题,需要底层基础设施具备极高的性能与稳定性。C++凭借其零成本抽象、直接内存操作能力以及对硬件细节的精细控制,成为构建此类高性能通信中间件与资源调度器的关键技

weixin_30383279的博客 349

C++低时延系统优化:从内核调优到零拷贝传输实战

在实时计算领域,低时延是衡量系统性能的核心指标,尤其在金融交易、在线游戏和自动驾驶等场景中,微秒级的延迟差异可能带来截然不同的结果。其技术原理涉及从硬件资源管理到软件架构设计的全链路优化,核心在于减少数据路径上的非必要开销。实现低时延的技术价值在于提升系统响应速度和确定性,从而支撑高并发、高可靠性的业务场景。具体到工程实践,这通常需要综合运用内核优化、高效内存管理和网络协议栈调优等手段。其中,DPDK和零拷贝传输技术是关键突破点,它们通过绕过内核和减少数据复制次数,将网络处理延迟降至微秒级。本文聚焦于C++

fanjava 315

DPDK环境准备实战:大页内存、CPU亲和与vfio-pci绑定避坑

用户态网络通过绕过内核协议栈,将收发包、内存访问和线程调度交由应用直接管理,以轮询、零拷贝和亲和性绑定降低单包处理开销。其技术价值在于把中断、上下文切换和内存拷贝带来的确定性损耗压到更低,适用于高吞吐、低时延的数据平面场景。落地时,大页内存、CPU亲和性、IOMMU与vfio-pci设备直通、NUMA对齐等基础配置必须先于业务代码就位,否则容易出现大页不足、网卡未绑定、跨节点访问和性能抖动。围绕DPDK环境准备,从硬件固件核对、系统底座配置到testpmd自检与报错定位,建立可复用的检查链路,才能让高性能转

weixin_29210727的博客 194

【紧迫预警】再不布局国产C++通信栈,AI算力优化将陷入停滞?

突破AI算力优化瓶颈,需重构底层通信架构。2025全球C++及系统软件技术大会“AI算力与优化”专场:C++通信库的国产化替代案例,揭示高性能计算场景下国产C++通信栈的设计方法与落地实践,显著降低延迟、提升吞吐。自主可控技术路径已验证,值得收藏,点击了解详情。

CompiWander的博客 918
上一篇: 【C/C++】手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发
SilentSlot
博客等级 码龄16年 44粉丝 68原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值