发布时间:2026/6/17 5:58:23
ngx_event_accept
1 定义ngx_event_accept 函数 定义在 ./nginx-1.24.0/src/event/ngx_event_accept.c2 作用ngx_event_accept 是 Nginx 中处理新连接到达的核心函数。 它从监听套接字上 accept 新的客户端连接 为其创建并初始化 ngx_connection_t 结构体 然后调用监听端口配置的 handler 将连接交给上层协议如 HTTP处理。3 详解1 函数签名voidngx_event_accept(ngx_event_t*ev)1. 返回值类型 void 含义 函数不返回任何值调用者无法获得操作成功或失败的直接反馈。 ngx_event_accept 是一个 事件处理器event handler 由事件框架在监听套接字上有新连接到达时回调。 它的职责是 “尽可能地接受并初始化新连接” 然后将连接交给上层协议如 HTTP处理而不需要向事件分发器汇报结果。 函数内部遇到的所有错误 都会被当场处理 记录日志、暂时禁用监听事件、释放资源等。 上层事件循环无需知道每次 accept 的细节只需继续等待下一次事件。2. 函数名 ngx_event_accept 命名空间前缀 ngx_Nginx 函数的标准前缀。 event_accept 准确描述了函数的用途 —— 处理监听套接字上的 “可接受新连接” 事件。 event表明这是一个事件处理函数。 accept直接对应 TCP 的 accept 系统调用表示接收新连接。 整体语义 该函数是 Nginx 中所有监听端口上新连接到达的统一入口。 无论是 HTTP、HTTPS、Stream 还是 Mail 当监听 socket 上有新连接时 最终都会调用此函数来执行 accept 并初始化连接。3. 参数 ngx_event_t *ev 类型 指向 ngx_event_t 结构体的指针 这是 Nginx 事件系统的核心数据结构代表一个 注册在事件驱动机制中的事件。总结 ngx_event_accept 的函数签名是 Nginx 事件处理器接口的经典范例 - void 返回值 体现了回调函数的 “执行并遗忘” 特性错误处理内聚在函数内部。 - 函数名直接揭示了它的业务含义处理 TCP 连接的 accept 事件。 - 唯一的 ev 参数 作为事件对象的抽象承载了触发上下文的所有信息 使得框架能够以极简的接口驱动复杂的网络 I/O 处理。2 逻辑流程1 文件描述符耗尽时的延迟重试 2 设置一次性接受连接的数量 3 接受新连接 3-1 提取监听连接与监听配置重置 ready 标志 3-2 循环持续接受新连接 3-2-1 调用 accept 获取新套接字 3-2-2 accept 失败 3-2-3 accept 成功{socklen_tsocklen;ngx_err_terr;ngx_log_t*log;ngx_uint_tlevel;ngx_socket_ts;ngx_event_t*rev,*wev;ngx_sockaddr_tsa;ngx_listening_t*ls;ngx_connection_t*c,*lc;ngx_event_conf_t*ecf;#if(NGX_HAVE_ACCEPT4)staticngx_uint_tuse_accept41;#endif局部变量1 文件描述符耗尽时的延迟重试if(ev-timedout){if(ngx_enable_accept_events((ngx_cycle_t*)ngx_cycle)!NGX_OK){return;}ev-timedout0;}当服务器因为文件描述符耗尽而暂时无法接受新连接时 通过定时器延迟重试并在重试时恢复监听。if (ev-timedout) { timedout 是一个标志位 当一个事件被触发不是因为它所等待的 I/O 操作就绪 而是因为一个关联的 定时器超时 了Nginx 就会将该事件的 timedout 设置为 1。 什么时候会发生这种情况 当 worker 进程的可用连接数文件描述符达到了上限worker_connections 它就无法再调用 accept 接受新连接。 此时Nginx 会把这个监听事件从 epoll 等事件驱动模块中暂时移除disable 避免 epoll 持续报告可读事件同时设置一个定时器。 当定时器到期后事件模块会再次触发这个监听事件并标记 ev-timedout 1 于是 ngx_event_accept 被调用 进入这个条件 调用 ngx_enable_accept_events 重新尝试恢复监听事件以便继续接受新连接if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) ! NGX_OK) { 它的作用是 重新将之前被移除的监听事件注册到事件驱动模块中。 返回值检查 该函数返回 NGX_OK 表示重新启用监听事件成功否则表示失败。 如果失败意味着无法恢复监听那么继续执行 accept 也没有意义 所以直接 return退出当前事件处理。ev-timedout 0; 成功重新启用监听事件后将 ev-timedout 标志 清零 这样下次该事件被触发时 timedout 已经恢复为初始状态0 避免错误地再次进入这个超时处理分支。总结 这段代码实现了 Nginx 在 文件描述符耗尽 时的一种 延迟重试 机制 1. 当连接数满 worker 进程无法 accept它不会忙等而是主动移除了监听事件并设置定时器。 2. 超时后重试 定时器到期后事件回调再次进入 ngx_event_accept 但此时 timedout1表明这不是真正的新连接到达而是一次 “请重新尝试监听” 的通知。 3. 恢复监听 代码检查到超时标志就调用 ngx_enable_accept_events 将监听事件重新加回 epoll。 如果恢复成功则清除标志如果恢复失败则直接返回等待后续可能的再次尝试。2 设置一次性接受连接的数量ecfngx_event_get_conf(ngx_cycle-conf_ctx,ngx_event_core_module);if(!(ngx_event_flagsNGX_USE_KQUEUE_EVENT)){ev-availableecf-multi_accept;}获取事件核心模块的配置判断当前使用的事件模型是否为 Kqueue 在 Kqueue 模型中监听事件返回时 内核会直接告诉应用程序当前有多少个新连接已经就绪 这个数值会被填充到 ev-available 中。 因此 Kqueue 下 ev-available 的值是由内核提供的准确数量不应该被配置覆盖。 所以代码跳过了对它的赋值直接保留内核给出的值。设置 ev-available 的值 ecf-multi_accept 是 multi_accept 指令的值。 这是一个配置指令可以设置为 on 或 off。 当 multi_accept off 时该值为 0。 当 multi_accept on 时该值为 1 ev-available 是 ngx_event_t 结构体中的一个整型字段。 在 accept 过程中它作为一个循环控制变量使用 函数末尾是一个 do ... while (ev-available) 循环 只要 ev-available 的值不为 0循环就会继续尝试 accept 更多的连接。3 接受新连接lcev-data;lslc-listening;ev-ready0;提取监听连接与监听配置重置 ready 标志ngx_log_debug2(NGX_LOG_DEBUG_EVENT,ev-log,0,accept on %V, ready: %d,ls-addr_text,ev-available);do{socklensizeof(ngx_sockaddr_t);#if(NGX_HAVE_ACCEPT4)if(use_accept4){saccept4(lc-fd,sa.sockaddr,socklen,SOCK_NONBLOCK);}else{saccept(lc-fd,sa.sockaddr,socklen);}#elsesaccept(lc-fd,sa.sockaddr,socklen);#endif调用 accept 获取新套接字处理 accept 失败if(s(ngx_socket_t)-1){errngx_socket_errno;if(errNGX_EAGAIN){ngx_log_debug0(NGX_LOG_DEBUG_EVENT,ev-log,err,accept() not ready);return;}levelNGX_LOG_ALERT;if(errNGX_ECONNABORTED){levelNGX_LOG_ERR;}elseif(errNGX_EMFILE||errNGX_ENFILE){levelNGX_LOG_CRIT;}#if(NGX_HAVE_ACCEPT4)ngx_log_error(level,ev-log,err,use_accept4?accept4() failed:accept() failed);if(use_accept4errNGX_ENOSYS){use_accept40;ngx_inherited_nonblocking0;continue;}#elsengx_log_error(level,ev-log,err,accept() failed);#endifif(errNGX_ECONNABORTED){if(ngx_event_flagsNGX_USE_KQUEUE_EVENT){ev-available--;}if(ev-available){continue;}}if(errNGX_EMFILE||errNGX_ENFILE){if(ngx_disable_accept_events((ngx_cycle_t*)ngx_cycle,1)!NGX_OK){return;}if(ngx_use_accept_mutex){if(ngx_accept_mutex_held){ngx_shmtx_unlock(ngx_accept_mutex);ngx_accept_mutex_held0;}ngx_accept_disabled1;}else{ngx_add_timer(ev,ecf-accept_mutex_delay);}}return;}accept 成功#if(NGX_STAT_STUB)(void)ngx_atomic_fetch_add(ngx_stat_accepted,1);#endifngx_accept_disabledngx_cycle-connection_n/8-ngx_cycle-free_connection_n;计算 ngx_accept_disabled 若空闲连接池剩余数量低于总容量的 1/8计算结果为正数后续将触发接收节流机制。cngx_get_connection(s,ev-log);if(cNULL){if(ngx_close_socket(s)-1){ngx_log_error(NGX_LOG_ALERT,ev-log,ngx_socket_errno,ngx_close_socket_n failed);}return;}为新连接分配连接对象c-typeSOCK_STREAM;设置连接类型 将连接的类型设置为 SOCK_STREAM表示这是一个 TCP 流式连接。#if(NGX_STAT_STUB)(void)ngx_atomic_fetch_add(ngx_stat_active,1);#endifc-poolngx_create_pool(ls-pool_size,ev-log);if(c-poolNULL){ngx_close_accepted_connection(c);return;}创建连接专属内存池if(socklen(socklen_t)sizeof(ngx_sockaddr_t)){socklensizeof(ngx_sockaddr_t);}c-sockaddrngx_palloc(c-pool,socklen);if(c-sockaddrNULL){ngx_close_accepted_connection(c);return;}ngx_memcpy(c-sockaddr,sa,socklen);保存客户端地址logngx_palloc(c-pool,sizeof(ngx_log_t));if(logNULL){ngx_close_accepted_connection(c);return;}分配日志对象设置套接字的阻塞或非阻塞模式/* set a blocking mode for iocp and non-blocking mode for others */if(ngx_inherited_nonblocking){if(ngx_event_flagsNGX_USE_IOCP_EVENT){if(ngx_blocking(s)-1){ngx_log_error(NGX_LOG_ALERT,ev-log,ngx_socket_errno,ngx_blocking_n failed);ngx_close_accepted_connection(c);return;}}}else{if(!(ngx_event_flagsNGX_USE_IOCP_EVENT)){if(ngx_nonblocking(s)-1){ngx_log_error(NGX_LOG_ALERT,ev-log,ngx_socket_errno,ngx_nonblocking_n failed);ngx_close_accepted_connection(c);return;}}}ngx_inherited_nonblocking 一个全局标志指示新接受的套接字是否已经自动设置为非阻塞。 在 Linux 上如果使用了 accept4 并成功这个标志为 1如果没有则需要手动设置。 IOCP 特殊处理IOCPWindows 下的完成端口需要套接字为阻塞模式 所以如果当前事件模型是 IOCP则调用 ngx_blocking 将套接字设为阻塞。 其他事件模型 默认epoll, kqueue 等都要求非阻塞模式 因此如果继承的非阻塞标志为 0即需要手动设置 且不是 IOCP 模型则调用 ngx_nonblocking 设置 O_NONBLOCK 标志。 任何设置失败都会关闭连接并返回确保后续不会在错误的阻塞模式下运行。*logls-log;初始化日志c-recvngx_recv;c-sendngx_send;c-recv_chainngx_recv_chain;c-send_chainngx_send_chain;初始化 基础接收/发送函数 recv、send基本的接收和发送函数对应系统调用 read/write 的封装。 recv_chain、send_chain用于处理 ngx_chain_t 链表形式的批量收发c-loglog;c-pool-loglog;将连接对象和连接内存池的日志指针都指向新创建的日志对象。 这样通过连接或池进行任何内存分配或日志输出都会使用同一个日志上下文c-socklensocklen;c-listeningls;c-local_sockaddrls-sockaddr;c-local_socklenls-socklen;保存监听配置和地址信息 将客户端地址长度、监听配置结构体指针、 本地监听地址及长度保存到连接对象中。 这些信息后续可能用于日志、匹配虚拟主机、连接管理等功能。Unix 域套接字的特殊处理#if(NGX_HAVE_UNIX_DOMAIN)if(c-sockaddr-sa_familyAF_UNIX){c-tcp_nopushNGX_TCP_NOPUSH_DISABLED;c-tcp_nodelayNGX_TCP_NODELAY_DISABLED;#if(NGX_SOLARIS)/* Solariss sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */c-sendfile0;#endif}#endif获取读写事件对象并设置初始状态revc-read;wevc-write;wev-ready1;写事件初始设为就绪ready 1 表示连接一建立就可以发送数据if(ngx_event_flagsNGX_USE_IOCP_EVENT){rev-ready1;}对于 IOCP 模型读事件也初始设为就绪因为 IOCP 的接受方式不同。if(ev-deferred_accept){rev-ready1;#if(NGX_HAVE_KQUEUE||NGX_HAVE_EPOLLRDHUP)rev-available1;#endif}果监听套接字上设置了 deferred_accept 选项TCP_DEFER_ACCEPT 则 accept 返回的连接上已经有数据到达客户端的第一个数据包已经在内核缓冲区中 因此读事件可以立即认为是就绪的从而直接开始读取请求减少一次事件循环。 rev-available 1 表示有数据可读。rev-loglog;wev-loglog;将读写事件的日志对象也指向新连接的日志对象以便事件处理时输出日志/* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */c-numberngx_atomic_fetch_add(ngx_connection_counter,1);c-start_timengx_current_msec;分配连接编号和记录开始时间#if(NGX_STAT_STUB)(void)ngx_atomic_fetch_add(ngx_stat_handled,1);#endif统计已处理的连接数生成客户端地址的可读文本if(ls-addr_ntop){c-addr_text.datangx_pnalloc(c-pool,ls-addr_text_max_len);if(c-addr_text.dataNULL){ngx_close_accepted_connection(c);return;}c-addr_text.lenngx_sock_ntop(c-sockaddr,c-socklen,c-addr_text.data,ls-addr_text_max_len,0);if(c-addr_text.len0){ngx_close_accepted_connection(c);return;}}#if(NGX_DEBUG){ngx_str_taddr;u_char text[NGX_SOCKADDR_STRLEN];ngx_debug_accepted_connection(ecf,c);if(log-log_levelNGX_LOG_DEBUG_EVENT){addr.datatext;addr.lenngx_sock_ntop(c-sockaddr,c-socklen,text,NGX_SOCKADDR_STRLEN,1);ngx_log_debug3(NGX_LOG_DEBUG_EVENT,log,0,*%uA accept: %V fd:%d,c-number,addr,s);}}#endif调试日志输出非 epoll 事件模型下注册连接事件if(ngx_add_conn(ngx_event_flagsNGX_USE_EPOLL_EVENT)0){if(ngx_add_conn(c)NGX_ERROR){ngx_close_accepted_connection(c);return;}}对于 epollNginx 采用更高效的边沿触发模式并延迟添加事件 直到确实需要等待某个事件时才调用 ngx_add_event 因此这里对 epoll 模型跳过直接添加。对于其他模型则立即注册。log-dataNULL;log-handlerNULL;ls-handler(c);调用上层协议处理函数 ls-handler 是在配置监听端口时设置的回调函数 这个函数将接管连接开始读取请求、解析协议。从此该连接的生命周期就由上层协议模块管理。if(ngx_event_flagsNGX_USE_KQUEUE_EVENT){ev-available--;}Kqueue 模型下的 available 递减 在 Kqueue 模型中ev-available 初始由内核设置表示就绪的连接数。 每成功接受一个连接递减该计数器直到 0 时循环结束。}while(ev-available);循环条件 检查 ev-available 是否为非 0。 在非 Kqueue 模型中如果 multi_accept on ev-available 在函数开始时被设置为 1 并且循环内未被修改除非遇到 ECONNABORTED 等特定错误 因此会一直循环直到 accept 返回错误并触发 return从而跳出整个函数。 如果 multi_accept offev-available 为 0循环只执行一次。 这种设计让 multi_accept on 时 可以在一次事件处理中连续接受多个新连接 减少了事件循环的开销。#if(NGX_HAVE_EPOLLEXCLUSIVE)ngx_reorder_accept_events(ls);#endif}EPOLLEXCLUSIVE 重排接受事件 如果系统支持 EPOLLEXCLUSIVELinux 4.5并且监听套接字设置了该选项 则多个 worker 可能会同时监听同一个套接字 但在任一时刻只有一个 worker 被唤醒。 ngx_reorder_accept_events 用于在每次处理完一批新连接后 调整监听事件在 epoll 中的位置或优先级 以确保新连接能在不同的 worker 之间更公平地分布避免单个 worker 垄断。

相关新闻

2026年|20款实测横比论文降AI工具怎么选?一篇攻略帮你看懂
2026/6/17 5:58:23

2026年|20款实测横比论文降AI工具怎么选?一篇攻略帮你看懂

咱学生党写论文,现在最挠头的压根不是查重率!是那红得刺眼的AIGC检测率!明明熬了好几个通宵改的稿子,怎么就被判成“AI生成”?改到凌晨AI率反而蹭蹭往上窜?为了帮大家避坑,我把市面上20多款主流…

阅读更多
Python与VS Code开发环境搭建:从零配置到高效编程
2026/6/17 4:58:23

Python与VS Code开发环境搭建:从零配置到高效编程

1. 项目概述:为什么是Python和VS Code的组合?如果你刚开始接触编程,或者从其他语言转向Python,听到最多的建议之一可能就是“装个VS Code吧”。这个组合几乎成了现代Python开发的“标准起手式”。我自己从早期的记事本、到各种IDE…

阅读更多
VC++ 2019运行库便携化实战:解决DLL依赖与部署难题
2026/6/17 4:58:23

VC++ 2019运行库便携化实战:解决DLL依赖与部署难题

1. 项目概述:为什么我们需要一个“便携版”的VC 2019?如果你是一个经常在不同电脑上折腾软件、或者需要给客户部署自己用Visual Studio 2019开发的C程序的开发者,那你一定对“DLL地狱”不陌生。你精心编写的程序,在你自己电脑上跑…

阅读更多
2026年AI最火趋势:掌握Agentic Engineering
2026/6/17 6:58:24

2026年AI最火趋势:掌握Agentic Engineering

2026 年,AI 圈最火的词是 Agentic Engineering。 Karpathy 在 2 月给了这个时代一个名字: “你 99% 的时间不在写代码。你在编排 Agent,充当监督者。” 3 月 7 日,他把这件事推到了极致——推送了一个 630 行的 Python 脚本&am…

阅读更多
性能测试实战:从JMeter工具使用到系统瓶颈定位的完整指南
2026/6/17 6:58:24

性能测试实战:从JMeter工具使用到系统瓶颈定位的完整指南

1. 项目概述:一次经典性能测试案例的深度复盘十多年前,也就是2013年,我参加了软件设计师(中级)的考试。那场考试里,一道关于“性能测试案例分析”的题目给我留下了极其深刻的印象。它不像现在很多题目那样&…

阅读更多
Kali Linux命令实战指南:从零掌握网络安全测试基础
2026/6/17 6:58:24

Kali Linux命令实战指南:从零掌握网络安全测试基础

1. 为什么你需要这份Kali Linux命令指南?如果你刚刚打开Kali Linux的终端,面对那个闪烁的光标感到一丝茫然,或者你已经在网上看过一些零散的教程,但总觉得命令记不住、用不熟,那么你来对地方了。我刚开始接触安全测试和…

阅读更多
ALE-LSA方法在气泡稳定性分析中的应用与验证
2026/6/17 6:58:24

ALE-LSA方法在气泡稳定性分析中的应用与验证

1. ALE-LSA方法概述:气泡稳定性分析的计算利器在计算流体力学(CFD)领域,稳定性分析是揭示流动失稳机制的关键技术。ALE-LSA(Arbitrary Lagrangian-Eulerian Linear Stability Analysis)方法作为一种先进的流固耦合分析工具&#x…

阅读更多
NXP QorIQ平台USDPAA框架下SRIO与RMU驱动配置与性能调优实战
2026/6/17 6:58:24

NXP QorIQ平台USDPAA框架下SRIO与RMU驱动配置与性能调优实战

1. 项目概述与核心价值在嵌入式系统,尤其是多核处理器和异构计算平台的设计中,处理器内核之间、处理器与协处理器或高速外设之间的数据交换瓶颈,往往是制约系统性能的致命短板。传统的内存共享或总线通信方式,在延迟、带宽和软件开…

阅读更多
ControlNet-v1-1 FP16完全指南:如何在低显存下实现专业级AI图像控制
2026/6/17 5:58:23

ControlNet-v1-1 FP16完全指南:如何在低显存下实现专业级AI图像控制

ControlNet-v1-1 FP16完全指南:如何在低显存下实现专业级AI图像控制 【免费下载链接】ControlNet-v1-1_fp16_safetensors 项目地址: https://ai.gitcode.com/hf_mirrors/comfyanonymous/ControlNet-v1-1_fp16_safetensors ControlNet-v1-1_fp16_safetensors…

阅读更多
别再只用BERT了!用Transformers库的AutoModel,5分钟搞定文本相似度计算(附代码对比)
2026/6/16 18:17:55

别再只用BERT了!用Transformers库的AutoModel,5分钟搞定文本相似度计算(附代码对比)

超越BERT:用Transformers库高效实现文本相似度计算的三种实战方案在自然语言处理领域,文本相似度计算是信息检索、问答系统和推荐系统等应用的核心技术。传统方法如TF-IDF或Word2Vec已逐渐被基于Transformer的预训练模型所取代。Hugging Face的Transform…

阅读更多
Prompt Engineering:重构人机协作的工程化方法论
2026/6/16 20:00:23

Prompt Engineering:重构人机协作的工程化方法论

1. 项目概述:这不是“写提示词”,而是重构人机协作的底层逻辑“Prompt Engineering”这个词,这两年被讲得太多,也太轻飘。很多人把它理解成“给AI发指令的技巧”,甚至简化为“多加几个形容词”“换种说法再试一次”。我…

阅读更多
Anthropic提示层归零:模型即协议的工程实践
2026/6/16 0:39:53

Anthropic提示层归零:模型即协议的工程实践

1. 项目概述:这不是一次普通更新,而是一次架构级“蒸发”“Anthropic Just Shipped the Layer That’s Already Going to Zero”——这个标题一出来,我正在调试一个Claude调用链的终端前停了三秒。不是因为震惊,而是因为熟悉&…

阅读更多
Alice-Tools:解密AliceSoft游戏文件的终极工具集
2026/6/17 0:58:23

Alice-Tools:解密AliceSoft游戏文件的终极工具集

Alice-Tools:解密AliceSoft游戏文件的终极工具集 【免费下载链接】alice-tools Tools for extracting/editing files from AliceSoft games. 项目地址: https://gitcode.com/gh_mirrors/al/alice-tools 对于AliceSoft游戏爱好者和开发者来说,处理…

阅读更多
基于Python的酒店预订管理系统设计与实现
2026/6/17 0:58:23

基于Python的酒店预订管理系统设计与实现

第1章 绪论1.1 课题背景由于旅游业的发展和互联网技术的不断进步,酒店预订系统已经成为现代旅游业不可或缺的部分,传统的酒店预定方式存在着流程繁琐、效率低等问题,不能满足现代消费者对个性化、便捷化越来越高的需求,因此开发…

阅读更多
生成式引擎优化GEO,原来选对服务商这么重要?
2026/6/17 0:58:23

生成式引擎优化GEO,原来选对服务商这么重要?

引言在当今数字化时代,生成式引擎优化(GEO)已经成为企业提升效率、降低成本的关键技术之一。然而,选择合适的GEO源头服务商却是一个复杂且重要的决策。本文将深入探讨为什么选对GEO服务商如此重要,并提供一些实用的选型…

阅读更多
GIT修改用户名
2026/6/16 5:55:51

GIT修改用户名

在GIT中修改用户名可按以下步骤操作: 查看当前git的用户名,使用命令git config --list或git config user.name。修改git用户名,使用命令git config --global user.name "xxx(新的用户名)",将其中…

阅读更多
Win11Debloat:让你的Windows系统重获新生的终极优化工具
2026/6/16 16:55:24

Win11Debloat:让你的Windows系统重获新生的终极优化工具

Win11Debloat:让你的Windows系统重获新生的终极优化工具 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter and …

阅读更多
技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践
2026/6/17 4:21:30

技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践

技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter m4s-converter是一个…

阅读更多