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

架构自定义UDP协议视频传输调试

一、整体系统架构图┌─────────────────────────────────────────────────────────────────┐ │ 视频流应用程序 │ │ test_stream │ └─────────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 发送端模块 │ │ 接收端模块 │ │ 双工模块 │ │ STREAM_ROLE_ │ │ STREAM_ROLE_ │ │ STREAM_ROLE_ │ │ SENDER │ │ RECEIVER │ │ DUPLEX │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ StreamContext │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 网络模块 │ │ RTP模块 │ │ 抖动缓冲 │ │ 帧队列 │ │ │ │ UDPContext │ │ RTPPacket │ │JitterBuffer │ │ FrameQueue │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 调试工具模块 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 日志系统 │ │性能计数器 │ │ 内存跟踪 │ │ 网络分析 │ │ │ │ debug_log │ │perf_counter │ │memory_trace │ │packet_capture│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────┘二、模块详细流程图2.1 发送端数据流程图┌─────────────────────────────────────────────────────────────────┐ │ 发送端数据流 │ └─────────────────────────────────────────────────────────────────┘ ​ 应用层 ┌──────────────┐ │ 视频帧数据 │ (H264 NAL单元) └──────┬───────┘ │ stream_send_frame() ▼ ┌─────────────────────────────────────────────────────────────────┐ │ StreamContext (发送端) │ ├─────────────────────────────────────────────────────────────────┤ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ stream_process_send_frame() │ │ │ │ ┌─────────────┐ │ │ │ │ │ 创建H264NALU │ │ │ │ │ └──────┬──────┘ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │rtp_from_h264_ │ ┌─────────────────┐ │ │ │ │ │nalu() │─▶│ 单NAL单元模式 │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │rtp_from_h264_ │─▶│ FU-A分片模式 │ │ │ │ │ │nalu() │ └─────────────────┘ │ │ │ │ └─────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ RTPPacket数组 │ [packet0, packet1, ...] │ │ │ │ └──────┬──────┬───┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │设置RTP头部 │ sequence timestamp ssrc │ │ │ │ └──────┬──────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │rtp_packet_ │ serialize RTP包到缓冲区 │ │ │ │ │serialize() │ │ │ │ │ └──────┬──────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────┐ │ │ │ │ │ udp_send() │ ────┐ │ │ │ │ └─────────────────┘ │ │ │ │ └────────────────────────────┼──────────────────────────────┘ │ └───────────────────────────────┼──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 网络层 (UDP传输) │ ├─────────────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ │ │ │ udp_sendto() │ │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ socket() │─▶│ sendto() │─▶│ 网络接口 │ │ │ └─────────────────┘ └─────────────────┘ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ 局域网 │ │ │ │ UDP包传输 │ │ │ └─────────────────┘ │ └─────────────────────────────────────────────────────────────────┘2.2 接收端数据流程图┌─────────────────────────────────────────────────────────────────┐ │ 接收端数据流 │ └─────────────────────────────────────────────────────────────────┘ ​ 网络层 ┌─────────────────────────────────────────────────────────────────┐ │ UDP网络接收 │ ├─────────────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ │ │ │ udp_recvfrom() │ │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ NetBuffer │ (原始UDP数据) │ │ └────────┬────────┘ │ └───────────┼──────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ StreamContext (接收端) │ ├─────────────────────────────────────────────────────────────────┤ │ ┌─────────────────┐ │ │ │rtp_packet_ │ 解析RTP包头 │ │ │parse() │ │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │rtp_packet_clone │ 克隆RTP包用于缓冲 │ │ └────────┬────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 抖动缓冲 (JitterBuffer) │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ jitter_buffer_insert() │ │ │ │ │ │ ┌─────────────┐ │ │ │ │ │ │ │查找槽位 │ │ │ │ │ │ │ └──────┬──────┘ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌─────────────┐ │ │ │ │ │ │ │检测丢包 │ jitter_buffer_detect_loss() │ │ │ │ │ │ └──────┬──────┘ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌─────────────┐ │ │ │ │ │ │ │插入到槽位 │ 环形缓冲区 │ │ │ │ │ │ └──────┬──────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ │ │ │ │ JitterBuffer环形缓冲区 │ │ │ │ │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ │ │ │ │ │ │slot0│ │slot1│ │slot2│ │... │ │slotN│ │ │ │ │ │ │ │ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ 帧组装 (Frame Assembly) │ │ │ │ │ │ ┌───────────────────────────────────────────────┐ │ │ │ │ │ │ │ jitter_buffer_assemble_frame() │ │ │ │ │ │ │ │ 1. 找到最早到达的包 │ │ │ │ │ │ │ │ 2. 收集同时间戳的所有包 │ │ │ │ │ │ │ │ 3. 检查帧完整性 │ │ │ │ │ │ │ │ 4. 合并所有分片 │ │ │ │ │ │ │ │ 5. 添加H264起始码 │ │ │ │ │ │ │ └───────────────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ 帧队列 (FrameQueue) │ │ │ │ │ │ ┌───────────────────────────────────────────────┐ │ │ │ │ │ │ │ frame_queue_push() │ │ │ │ │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ │ │ │ │ │ │帧1 │→│帧2 │→│帧3 │ (链表队列) │ │ │ │ │ │ │ │ └─────┘ └─────┘ └─────┘ │ │ │ │ │ │ │ └───────────────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 应用层接口 │ │ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ │ │ stream_receive_frame() │ │ │ │ │ │ frame_queue_pop() (等待帧可用) │ │ │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ │ │ stream_free_frame() (释放帧内存) │ │ │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘2.3 抖动缓冲内部状态机┌─────────────────────────────────────────────────────────────────┐ │ 抖动缓冲状态机 │ └─────────────────────────────────────────────────────────────────┘ ​ 包到达 │ ▼ ┌─────────────────────────────────────┐ │ jitter_buffer_insert() │ └─────────────────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 查找插入位置 │ │ find_slot() │ └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 检测丢包 │ │ detect_loss() │ └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 插入环形缓冲区 │ │ insert_at() │ └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 更新统计信息 │ │ update_stats() │ └─────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 自适应延迟调整 │ │ update_delay() │ └─────────────────────────┘ │ ▼ ┌─────────────────────────────────┐ │ 定时检查帧完整性 │ └─────────────────────────────────┘ │ ┌───────────┴───────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ 帧完整 │ │ 帧不完整 │ │ frame_complete │ │ frame_incomplete│ └────────┬────────┘ └────────┬────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ 组装帧 │ │ 等待更多包 │ │ assemble_frame │ │ wait_for_packets│ └────────┬────────┘ └─────────────────┘ │ │ ▼ │ ┌─────────────────┐ │ │ 放入帧队列 │ │ │ frame_queue │ │ └─────────────────┘ │ │ │ └───────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 清理过期包 │ │ clean_old() │ └─────────────────────────┘2.4 线程模型流程图┌─────────────────────────────────────────────────────────────────┐ │ 多线程协作模型 │ └─────────────────────────────────────────────────────────────────┘ ​ 主线程 (Main Thread) ┌─────────────────────────────────────────────────────────────────┐ │ stream_create() → 初始化各个模块 │ │ stream_start() → 创建工作线程 │ │ │ │ │ ├──→ 创建发送线程 (Send Thread) │ │ ├──→ 创建接收线程 (Receive Thread) │ │ └──→ 创建统计线程 (Stats Thread) │ │ │ │ stream_stop() → 停止工作线程 │ │ stream_destroy() → 清理资源 │ └─────────────────────────────────────────────────────────────────┘ ​ 发送线程 (Send Thread) ┌─────────────────────────────────────────────────────────────────┐ │ while(threads_running) { │ │ pthread_mutex_lock(thread_mutex); │ │ if (state PAUSED) │ │ pthread_cond_wait(thread_cond); │ │ pthread_mutex_unlock(thread_mutex); │ │ │ │ /* 等待帧数据从应用层来 */ │ │ /* 实际发送由stream_send_frame()触发 */ │ │ usleep(10000); /* 10ms心跳 */ │ │ } │ └─────────────────────────────────────────────────────────────────┘ ​ 接收线程 (Receive Thread) ┌─────────────────────────────────────────────────────────────────┐ │ while(threads_running) { │ │ /* 检查暂停状态 */ │ │ pthread_mutex_lock(thread_mutex); │ │ if (state PAUSED) │ │ pthread_cond_wait(thread_cond); │ │ pthread_mutex_unlock(thread_mutex); │ │ │ │ /* 接收UDP数据 */ │ │ udp_recvfrom() ───────────────────────────────────┐ │ │ │ │ │ │ ▼ │ │ │ rtp_packet_parse() │ │ │ │ │ │ │ ▼ │ │ │ jitter_buffer_insert() ─────────────────────────┐ │ │ │ │ │ │ │ │ ▼ │ │ │ │ jitter_buffer_read_frame() ──────────────────┐ │ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ frame_queue_push() │ │ │ │ │ │ │ │ │ │ │ └──────────────────────────────────────────┼──┼───────────┘ │ │ │ │ /* 循环直到没有更多完整帧 */ │ │ │ } │ │ └─────────────────────────────────────────────────────┼──┼───────────┘ │ │ 统计线程 (Stats Thread) │ │ ┌─────────────────────────────────────────────────────┼──┼───────────┐ │ while(threads_running) { │ │ │ │ sleep(1); /* 每秒更新 */ │ │ │ │ │ │ │ │ pthread_mutex_lock(stats_mutex); │ │ │ │ /* 计算码率 */ │ │ │ │ bitrate (bytes_diff * 8) / elapsed; │ │ │ │ │ │ │ │ /* 获取抖动缓冲统计 */ │ │ │ │ jitter_buffer_get_stats() ──────────────────────┘ │ │ │ │ │ │ /* 更新统计信息 */ │ │ │ pthread_mutex_unlock(stats_mutex); │ │ │ │ │ │ /* 可选打印统计信息 */ │ │ │ stream_dump_info(); │ │ │ } │ │ └──────────────────────────────────────────────────────────┼────────────┘ │ 应用线程 (Application Thread) │ ┌──────────────────────────────────────────────────────────┼────────────┐ │ /* 发送端调用 */ │ │ │ stream_send_frame() ─────────────────────────────────────┘ │ │ │ │ │ └──→ 触发发送线程处理 │ │ │ │ /* 接收端调用 */ │ │ stream_receive_frame() ───────────────────────────────────────────┐ │ │ │ │ │ │ └──→ frame_queue_pop() (可能阻塞等待帧) │ │ │ │ │ │ stream_free_frame() (释放帧内存) │ │ └────────────────────────────────────────────────────────────────────┼─┘ │ 调试线程 (可选) │ ┌────────────────────────────────────────────────────────────────────┼─┐ │ debug_thread() { │ │ │ while(1) { │ │ │ /* 定期检查内存泄漏 */ │ │ │ debug_check_leaks(); │ │ │ │ │ │ /* 收集性能数据 */ │ │ │ perf_counter_print_all(); │ │ │ │ │ │ sleep(60); /* 每分钟检查一次 */ │ │ │ } │ │ │ } │ │ └────────────────────────────────────────────────────────────────────┴─┘2.5 内存管理流程图┌─────────────────────────────────────────────────────────────────┐ │ 内存管理策略 │ └─────────────────────────────────────────────────────────────────┘ ​ 连续内存分配 (Contiguous) ┌─────────────────────────────────────────────────────────────────┐ │ [内存池起始] │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ MemHeader │ 数据块 │ MemHeader │ 数据块 │ MemHeader │ ... │ │ │ └───────────────────────────────────────────────────────────┘ │ │ ↑ ↑ ↑ ↑ │ │ 空闲链表头 已使用块 空闲块 已使用块 │ └─────────────────────────────────────────────────────────────────┘ ​ 分散内存分配 (Scattered) ┌─────────────────────────────────────────────────────────────────┐ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ 块1 │ │ 块2 │ │ 块3 │ │ 块4 │ (不连续) │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ │ └────────────┼────────────┼────────────┘ │ │ │ │ │ │ ┌─────▼────────────▼─────┐ │ │ │ 内存池管理链表 │ │ │ └────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ​ 内存池操作流程 ┌─────────────────────────────────────────────────────────────────┐ │ memory_pool_alloc() │ │ │ │ 开始 ──────────────────────────────────────────────────────┐ │ │ │ │ │ │ ▼ │ │ │ 加锁 (pthread_mutex_lock) │ │ │ │ │ │ │ ▼ │ │ │ 遍历空闲链表 ──→ 找到第一个大小足够的块 ──→ 是否找到 │ │ │ │ │ │ │ │ │ │ │ ├─否→ 解锁 │ │ │ │ │ │ 返回NULL │ │ │ │ │ ▼ │ │ │ │ └─是→ 检查块大小 │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ 是否需要分割 │ │ │ │ │ │ │ │ │ │ │ ├─否→ 标记为已使用│ │ │ │ │ │ 更新统计 │ │ │ │ │ ▼ │ │ │ │ └─是→ 分割块 │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ 创建新空闲块 │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ 标记当前块为已使用 │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ 更新空闲链表 │ │ │ │ │ │ │ │ └────────────────────────────────────────────┼──────────────┘ │ │ │ │ │ ▼ │ │ 解锁 │ │ │ │ │ ▼ │ │ 返回数据指针 │ │ │ │ │ ▼ │ │ 结束 │ └─────────────────────────────────────────────────────────────────┘2.6 函数调用关系图┌─────────────────────────────────────────────────────────────────┐ │ 顶层函数调用关系 │ └─────────────────────────────────────────────────────────────────┘ ​ main() / test_stream ├── network_init() ├── debug_init() ├── stream_create() │ ├── udp_create() │ │ ├── socket() │ │ ├── setsockopt() │ │ └── bind() │ ├── jitter_buffer_create() │ │ └── calloc() │ └── frame_queue_create() │ ├── pthread_mutex_init() │ └── pthread_cond_init() │ ├── stream_start() │ ├── pthread_create() → stream_send_thread │ ├── pthread_create() → stream_recv_thread │ └── pthread_create() → stream_stats_thread │ ├── stream_send_frame() │ └── stream_process_send_frame() │ ├── rtp_from_h264_nalu() │ │ ├── rtp_pack_single_nalu() │ │ └── rtp_pack_fu_a() │ ├── rtp_packet_serialize() │ └── udp_send() │ └── udp_sendto() │ └── sendto() │ ├── stream_receive_frame() │ └── frame_queue_pop() │ ├── pthread_mutex_lock() │ ├── pthread_cond_wait() │ └── pthread_mutex_unlock() │ ├── stream_stop() │ ├── pthread_join() │ └── pthread_cond_broadcast() │ └── stream_destroy() ├── udp_destroy() │ └── close() ├── jitter_buffer_destroy() ├── frame_queue_destroy() └── free() ​ 接收线程函数调用链: stream_recv_thread() ├── udp_recvfrom() │ └── recvfrom() ├── rtp_packet_parse() ├── rtp_packet_clone() ├── jitter_buffer_insert() │ ├── jitter_buffer_find_slot() │ ├── jitter_buffer_detect_loss() │ └── jitter_buffer_insert_at() ├── jitter_buffer_read_frame() │ └── jitter_buffer_assemble_frame() └── frame_queue_push() ​ 统计线程函数调用链: stream_stats_thread() ├── jitter_buffer_get_stats() ├── stream_dump_info() └── perf_counter_print_all() └── debug_log() ​ 调试函数调用链: debug_log() ├── get_timestamp_str() ├── get_thread_id() ├── vfprintf() → stderr └── fprintf() → log file ​ debug_malloc() ├── malloc() └── debug_memory_alloc() ├── backtrace() └── debug_log()2.7 数据包处理流程┌─────────────────────────────────────────────────────────────────┐ │ RTP数据包处理流程 │ └─────────────────────────────────────────────────────────────────┘ ​ 发送方向 (从左到右): ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ H264帧 │───▶│NAL单元 │───▶│RTP包 │───▶│UDP数据报│───▶ 网络 └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ ▼ ▼ ▼ NAL类型: RTP头部: UDP头部: - SPS/PPS - Version2 - 源端口 - IDR帧 - Payload Type - 目的端口 - P帧 - Sequence - 长度 - FU-A分片 - Timestamp - 校验和 - SSRC ​ 接收方向 (从右到左): ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 网络 │───▶│UDP数据报│───▶│RTP包 │───▶│NAL单元 │───▶│H264帧 │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ ▼ ▼ ▼ ▼ UDP解包 RTP解析 NAL重组 帧组装 - 检查版本 - FU-A合并 - 添加起始码 - 验证SSRC - STAP-A拆分 - 时间戳管理 - 序列号处理 - NAL类型识别 - 关键帧检测 ​ RTP包格式: ┌─────────────────────────────────────────────────────────────┐ │ 0 1 2 3│ │ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1│ ├─────────────────────────────────────────────────────────────┤ │V2|P|X| CC |M| PT | sequence number │ ├─────────────────────────────────────────────────────────────┤ │ timestamp │ ├─────────────────────────────────────────────────────────────┤ │ synchronization source (SSRC) │ ├─────────────────────────────────────────────────────────────┤ │ contributing sources (CSRC) (optional) │ ├─────────────────────────────────────────────────────────────┤ │ payload data ... │ └─────────────────────────────────────────────────────────────┘2.8 调试工具架构┌─────────────────────────────────────────────────────────────────┐ │ 调试工具架构 │ └─────────────────────────────────────────────────────────────────┘ ​ ┌─────────────────────────────────────────────────────────────────┐ │ DebugContext │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 配置: global_level, module_levels, enable_color, ... │ │ │ ├───────────────────────────────────────────────────────────┤ │ │ │ 性能计数器数组: │ │ │ │ [0] nameudp_send, typeTIMER, count100, total... │ │ │ │ [1] namertp_parse, typeTIMER, count50, total... │ │ │ │ [2] namepacket_loss, typeCOUNTER, value5 │ │ │ ├───────────────────────────────────────────────────────────┤ │ │ │ 内存跟踪链表: │ │ │ │ ptr0x1234, size1024, filetest.c, line42 │ │ │ │ ptr0x5678, size2048, filejitter.c, line100 │ │ │ ├───────────────────────────────────────────────────────────┤ │ │ │ 统计信息: │ │ │ │ log_messages1000, errors5, warnings10 │ │ │ │ current_memory10240, peak_memory20480 │ │ │ └───────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ​ 日志系统流程图: ┌─────────────────────────────────────────────────────────────────┐ │ debug_log() │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 1. 检查日志级别是否启用 │ │ │ │ if (level module_level) return; │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 2. 获取时间戳和线程ID │ │ │ │ get_timestamp_str() │ │ │ │ get_thread_id() │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 3. 格式化日志消息 │ │ │ │ vsnprintf() │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 4. 输出到控制台带颜色 │ │ │ │ fprintf(stderr, %s%s%s, color, buffer, reset) │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 5. 输出到日志文件 │ │ │ │ if (log_file) fprintf(log_file, buffer) │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 6. 更新统计信息 │ │ │ │ stats.log_messages │ │ │ │ if (level ERROR) stats.errors │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ​ 性能计数器工作流程: ┌─────────────────────────────────────────────────────────────────┐ │ perf_counter_start() perf_counter_end() │ │ │ │ │ │ ▼ ▼ │ │ clock_gettime() clock_gettime() │ │ │ │ │ │ │ ▼ │ │ └─────────────────→ 计算时间差 │ │ │ │ │ ▼ │ │ 更新计数器: │ │ count │ │ total elapsed │ │ if (elapsed min) min elapsed │ │ if (elapsed max) max elapsed │ │ avg total / count │ │ │ └─────────────────────────────────────────────────────────────────┘ ​ 内存跟踪工作流程: ┌─────────────────────────────────────────────────────────────────┐ │ debug_malloc(size) debug_free(ptr) │ │ │ │ │ │ ▼ ▼ │ │ ptr malloc(size) debug_memory_free(ptr) │ │ │ │ │ │ ▼ ▼ │ │ debug_memory_alloc() 在链表中查找对应记录 │ │ │ │ │ │ ▼ ▼ │ │ 创建MemoryTrace记录 标记为freed │ │ │ │ │ │ ▼ ▼ │ │ 记录调用回溯 更新统计: │ │ backtrace() total_freed size │ │ current_memory - size │ │ free_count │ │ free(ptr) │ └─────────────────────────────────────────────────────────────────┘

相关文章:

架构自定义UDP协议视频传输调试

一、整体系统架构图┌─────────────────────────────────────────────────────────────────┐ │ 视频流应用程序 │ │ test_…...

基于协同过滤算法的音乐网站的设计与实现

目录 可选框架 可选语言 内容 可选框架 J2EE、MVC、vue3、spring、springmvc、mybatis、SSH、SpringBoot、SSM、django 可选语言 java、web、PHP、asp.net、javaweb、C#、python、 HTML5、jsp、ajax、vue3 内容 在互联网普及化的大背景下,音乐资源的过多带来…...

基于python的家庭消费数据分析系统的设计与实现

目录 可选框架 可选语言 内容 可选框架 J2EE、MVC、vue3、spring、springmvc、mybatis、SSH、SpringBoot、SSM、django 可选语言 java、web、PHP、asp.net、javaweb、C#、python、 HTML5、jsp、ajax、vue3 内容 由于大数据技术的快速发展,家庭消费数据分析的…...

C++虚函数:多态实现的关键基石

C 虚函数与纯虚函数:多态的核心实现基石在面向对象编程中,多态(Polymorphism)是一种核心特性,它允许不同类的对象对同一消息(如函数调用)做出不同响应。这种机制提高了代码的灵活性和可扩展性&a…...

仁王3的宏 和 浪人崛起 战神3模拟器设置 the dark rites of akham

the dark rites of akham: 卡关点: 地下室的box里面有刀. 警局垃圾箱里面有面包. 警局的玩硬币之后拿到硬币,之后去精神医院门口报纸机器拿报纸. 罐头打开之后放雨伞上. 互动大地图:https://www.gamersky.com/tools/map/rw3/ 用来找武士益发, 忍者益发. 仁王3里面99武器适合狂按…...

智慧课堂-YOLOv8课堂行为检测系统|学生+教师双模型|图片/视频/摄像头/双摄像头|历史记录+报告|Web可视化YOLOv8 课堂老师及学生行为检测系统 —— 学生+教师双模型智能分析平台

智慧课堂-YOLOv8课堂行为检测系统|学生教师双模型|图片/视频/摄像头/双摄像头|历史记录报告|Web可视化 包括 全部源码 完整标注的数据集 训练好的模型及训练结果 项目运行教程(README.md) 仅供参考系统…...

像素即坐标 · 视频即传感器 · 空间即智能——镜像视界 Pixel-to-Space 空间智能技术白皮书

像素即坐标 视频即传感器 空间即智能——镜像视界 Pixel-to-Space 空间智能技术白皮书发布单位:镜像视界(浙江)科技有限公司 发布时间:2026一、白皮书摘要随着人工智能、大模型技术和空间计算技术的快速发展,传统视频…...

Q61P三菱标准电源模块

Q61P 是三菱电机(Mitsubishi Electric)MELSEC-Q 系列 PLC 的标准电源模块,专为 Q 系列 CPU、I/O 及功能模块提供稳定的 DC 5V/6A 电源。一、产品特性类型:Q 系列 PLC 主基板电源模块(开关电源型)输入&#…...

QJ71GP21S-SX三菱网络模块

QJ71GP21S-SX 是三菱电机 MELSEC-Q 系列的 CC-Link IE 控制器网络模块(光纤型、双回路、带外部供电),专为中大型分布式控制系统提供 1Gbps 超高速、大容量、高可靠的 PLC 间互联与数据共享能力。一、产品特性1Gbps 超高速光纤通信&#xff1a…...

深入解析:高阶 iOS 工程师的技术栈、架构设计与民航行业应用实践

引言 在移动互联网高速发展的时代,iOS 应用作为连接用户与服务的重要桥梁,其质量、性能和用户体验至关重要。优秀的 iOS 工程师不仅需要扎实的语言基础和框架知识,还需具备良好的架构设计能力、复杂问题排查技巧,以及对特定行业业务逻辑的深刻理解。本文旨在深度剖析一份典…...

《OpenClaw 从入门到精通指南》正式发布,开源免费!

大家好,我是苍何。今天,我们打磨了很久的《OpenClaw 从入门到精通指南》终于正式和大家见面了。他是完全免费的,开源的。从 OpenClaw 还没大火的时候,我们就开始写这份文档,那个时候在 X 上先推了第一个版本&#xff0…...

基于多模态攻击链的网络钓鱼防御机制与韧性构建研究

摘要 网络钓鱼(Phishing)作为网络安全领域最为持久且演变迅速的威胁向量,已从早期的粗放式邮件欺诈演变为利用人工智能、自动化服务及社会工程学心理操纵的精密攻击体系。本文基于Consumer Affairs发布的最新深度报道,系统剖析了现…...

北京有没有可以做SMT贴片和整机组装的公司

随着电子信息产业的快速发展,电子制造服务(EMS)已成为产业链中至关重要的一环。北京作为中国的科技创新中心,汇聚了一批技术实力雄厚、制造能力卓越的电子制造企业,尤其在需要高精度、高可靠性的SMT(表面贴…...

基于Python的新能源汽车价格走势分析与可视化研究

摘 要随着全球能源危机和环境污染问题的日益严峻,新能源汽车作为传统燃油汽车的替代品,已成为汽车产业发展的重要方向。近年来,我国新能源汽车市场呈现爆发式增长态势,产销量连续多年位居全球第一。在市场竞争日益激烈的背景下&a…...

Linux 文件系统目录架构全解析

Linux 文件系统采用树形分层结构,以根目录 / 为起点,所有文件和目录都依附于这一核心节点。这种设计遵循 FHS(文件系统层次结构标准),让系统资源管理更清晰、协作更高效。下面我们逐一解析核心目录的作用&#xff1a…...

RVFLNN随机向量函数链神经网络:单变量时间序列预测的快速高精度模型

RVFLNN(Random vector functional link neural network )随机向量函数链神经网络 单变量时间序列预测 自带单变量数据 python 代码,模型部分是手撸的,当然不是我 数据格式为csv,可以替换成自己的 这个模型也不是最近的…...

MemEvolve·记忆与学习融合系统:给OpenClaw装上会“进化”的大脑,让AI在每一次对话中变得更懂你

大家好,我是芯作者,给大家分享下给OpenClaw装上会“进化”的大脑 当AI记住你所有的偏好,却永远学不会从错误中成长——这不是记忆,这是“死记硬背”。真正的智能,是在记住的同时,还能从每一次纠正中进化。 两大遗憾,一个解决方案 如果你已经用上了OpenClaw,你一定经历…...

ClawShield·智能体免疫系统:给OpenClaw装上“安全护栏”,让AI在动手前先问“我可以吗?”

hello大家好,我是芯作者,给大家分享下openclaw的安全护栏! 你以为装的只是一个查天气的Skill,实际上它正在悄悄把你的SSH密钥发给黑客。当AI开始真正动手干活,谁来保证它不“闯祸”? 当“小龙虾”开始咬人 2026年2月,VirusTotal接连发布两份重磅报告,揭露了OpenClaw生…...

杰理之开关IIS解码后,不停的打印“W“【篇】

显示buf满...

基于大数据的就业推荐系统设计与实现

目录 可选框架 可选语言 内容 可选框架 J2EE、MVC、vue3、spring、springmvc、mybatis、SSH、SpringBoot、SSM、django 可选语言 java、web、PHP、asp.net、javaweb、C#、python、 HTML5、jsp、ajax、vue3 内容 当今时代,随着信息技术的发展,世界…...

【揭秘】3大关键指标,你的耐燃烧试验机真的达标了吗?

在电子、汽车、航空航天等高端制造领域,产品的阻燃性能是关乎安全与合规的生命线。然而,许多企业实验室在进行耐燃烧测试时,常常陷入一个怪圈:测试周期冗长,数据重复性差,设备维护繁琐。这不仅拖慢了研发进…...

桶排序原理与Python实现详解

桶排序算法全面解析:原理、Python实现与动图演示 1. 算法概述 桶排序(Bucket Sort)是一种分布式排序算法,它将待排序的元素分布到有限数量的桶中,然后对每个桶中的元素进行排序,最后按照桶的顺序依次取出…...

微信 AI 小程序成长计划来了,我们怎么把混元接进了产品里

这段时间,微信生态对 AI 小程序的支持明显加速了。 从成长计划、云开发,到混元模型能力和商业化链路,平台给开发者补上的东西越来越多。 我们最近在做「好记好搜 AI 助手」时,也认真把这套能力研究了一遍,最后决定把混元接进产品里。 不过在接入方式上,我们没有选择“前端…...

Js: 标识符、关键字、保留字和运算符

一、标识符定义: 指开发人员为变量、属性、函数、参数取的名字注意: 标识符不能是关键字或保留字二、关键字定义: 指JS本身已经使用了的字,不能再用它们充当变量名、方法名三、保留字定义: 实际上就是预留的关键字,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不…...

探索 COMSOL 顺层钻孔瓦斯抽采:双孔隙介质数值模拟模型

comsol顺层钻孔瓦斯抽采,考虑瓦斯吸附解吸的双孔隙介质数值模拟模型最近在研究煤矿安全相关的问题,其中顺层钻孔瓦斯抽采是煤矿安全生产里极为关键的一环。而考虑瓦斯吸附解吸的双孔隙介质数值模拟模型就像一把钥匙,能帮助我们更好地理解和优…...

压缩文件怎么设置密码?RAR三种加密方法步骤

在日常工作与生活中,我们经常需要将重要文件通过压缩包的形式进行存储或传输。但你是否想过,如果这些文件包含商业合同、个人隐私或机密数据,一旦落入他人手中该如何是好?其实,WinRAR等压缩软件内置了强大的加密功能&a…...

网络共享-“引用的账户当前已锁定。且可能无法登陆”问题解决

已设置好电脑a 共享文件夹,但是电脑B无法访问,提示“无法访问,引用的账号当前已锁定,且可能无法登录”,其他电脑能够访问到共享文件夹,同一局域网另外一台电脑无法访问,最简单的解决办法就是A和…...

〘 8-1 〙软考高项 | 第15章:项目风险管理(上)

💡 点赞・能量加载 | 🌐 关注・持续更新 📎 收藏・方便回看 | ✨ 评论・互动交流 目录 1.项目风险管理概述 1.1 项目风险定义 1.2 风险的属性 1.3 风险的分类 1.4 风险成本 1.5 风险管理新实践 1.5.1 非事件类风险 1.5.2 项目…...

Day.js基本使用

在 Vue3 项目开发中,时间处理是绕不开的高频需求——比如格式化接口返回的时间戳、计算两个日期的差值、转换时区、展示相对时间(如“3分钟前”)。提到时间处理,很多开发者会先想到 Moment.js,但它体积偏大&#xff08…...

在AspNetCore中理解依赖注入生命周期冲突与解决方案

本文详细讲解AspNetCore依赖注入生命周期冲突问题,通过BackgroundService后台托管服务示例,分析Singleton、Scoped、Transient三种生命周期的区别及注入规则,重点说明为什么Singleton不能直接依赖Scoped服务,以及如何使用IService…...