尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

ngx_writev

ngx_writev
📅 发布时间:2026/7/22 3:09:36

1 定义

ngx_writev 函数 定义在 src/os/unix/ngx_writev_chain.c
ssize_tngx_writev(ngx_connection_t*c,ngx_iovec_t*vec){ssize_tn;ngx_err_terr;eintr:n=writev(c->fd,vec->iovs,vec->count);ngx_log_debug2(NGX_LOG_DEBUG_EVENT,c->log,0,"writev: %z of %uz",n,vec->size);if(n==-1){err=ngx_errno;switch(err){caseNGX_EAGAIN:ngx_log_debug0(NGX_LOG_DEBUG_EVENT,c->log,err,"writev() not ready");returnNGX_AGAIN;caseNGX_EINTR:ngx_log_debug0(NGX_LOG_DEBUG_EVENT,c->log,err,"writev() was interrupted");gotoeintr;default:c->write->error=1;ngx_connection_error(c,err,"writev() failed");returnNGX_ERROR;}}returnn;}

2 目的

1 设计意图

ngx_writev是 Nginx 对 POSIXwritev(2)系统调用的薄封装函数,
负责将一组struct iovec数组
一次性写入到 TCP 套接字文件描述符。
它是发送链路的最底层——直接与内核交互的系统调用入口。

2 上下游关系

ngx_writev_chain (发送链管理) │ 将 ngx_chain_t 链表转为 iovec 数组 │ 调用 ngx_writev 执行实际发送 ▼ ngx_writev (本函数) │ 1. 调用 writev(2) 系统调用 │ 2. 将 POSIX errno 映射为 Nginx 内部错误码 │ 3. 处理 EAGAIN / EINTR / 其他错误 ▼ writev() 系统调用 ──► 内核 TCP 协议栈

核心职责拆分:

  • 系统调用适配:
    将 Nginx 的ngx_iovec_t结构转换为 POSIXwritev的参数格式(vec->iovs、vec->count)。
  • 错误码归一化:
    将 POSIX 的errno(EAGAIN、EINTR等)映射为 Nginx 内部统一的错误码
    (NGX_AGAIN、NGX_ERROR),
    使上层调用者不直接依赖errno。
  • EINTR 安全重试:对信号中断(EINTR)自动重试,保证信号安全语义。
  • 调试日志:在每次系统调用后记录实际发送字节数与预期量的关系,便于问题排查。

3 详解

1 函数签名

ssize_tngx_writev(ngx_connection_t*c,ngx_iovec_t*vec)

1 返回值:ssize_t

返回值含义上层处理
> 0实际发送的字节数ngx_writev_chain据此推进链指针
NGX_AGAIN(-2)socket 发送缓冲区满,暂不可写调用者设置wev->ready = 0,等待事件通知后重试
NGX_ERROR(-1)发生不可恢复的错误(连接重置等)调用者返回NGX_CHAIN_ERROR,上层关闭连接

注意:本函数不会返回 0——POSIXwritev对 TCP 套接字不会返回 0


2 函数名:ngx_writev

词段含义
ngxNginx 命名空间前缀
writev直接对应 POSIXwritev(2)系统调用,表明这是一个系统调用的封装

3 参数列表

参数名类型含义来源约束
cngx_connection_t *目标 TCP 连接上层ngx_writev_chain的上游调用者传入非 NULL;c->fd为有效 socket fd;c->write指向写事件对象
vecngx_iovec_t *待发送的 iovec 数组封装ngx_writev_chain通过ngx_output_chain_to_iovec填充非 NULL;vec->iovs指向有效的 iovec 数组;vec->count为条目数

2 逻辑流程

ngx_writev(c, vec) │ ├─ [1] 调用 writev 系统调用 │ └─ n = writev(c->fd, vec->iovs, vec->count) │ ├─ [2] 调试日志 │ └─ 记录 "writev: %z of %uz",n 和 vec->size │ ├─ [3] 成功路径 │ └─ n != -1 → 返回 n(实际发送字节数) │ └─ [4] 错误路径(n == -1) ├─ err = ngx_errno(保存 errno) │ ├─ [4.1] EAGAIN 处理 │ └─ err == NGX_EAGAIN → 记录 "not ready",返回 NGX_AGAIN │ ├─ [4.2] EINTR 处理 │ └─ err == NGX_EINTR → 记录 "was interrupted",goto eintr 重试 │ └─ [4.3] 其他错误处理 └─ default → c->write->error = 1,记录日志,返回 NGX_ERROR

3 局部变量声明

{ssize_tn;ngx_err_terr;}

局部变量声明

  • n:保存writev的返回值(已发送字节数或 -1)。
  • err:保存 POSIXerrno的快照(见 [4] 分支的设计意图)。

1 调用 writev 系统调用

eintr:n=writev(c->fd,vec->iovs,vec->count);

进入条件:每次函数被调用时首先执行,以及 EINTR 重试时跳转至此。

处理逻辑:
调用 POSIXwritev(2)系统调用,执行 scatter-gather 写操作。参数:

  • c->fd:目标 socket 文件描述符。
    该 fd 在连接建立时被设置为非阻塞模式(O_NONBLOCK),
    因此writev不会阻塞进程。
  • vec->iovs:
    由调用者(ngx_output_chain_to_iovec)填充的struct iovec数组,
    每个元素包含iov_base(数据起始地址)和iov_len(数据长度)。
  • vec->count:
    iovec 数组中的有效条目数。

writev(2)是 POSIX.1-2001 标准系统调用(声明在<sys/uio.h>),
语义为"将多个不连续内存区域的数据一次性写入文件描述符"。
对于 TCP 套接字,实际发送的字节数可能小于请求的总字节数(vec->size)——
当内核发送缓冲区不足以容纳所有数据时,
writev会发送尽可能多的数据并返回实际发送量。


2 调试日志

ngx_log_debug2(NGX_LOG_DEBUG_EVENT,c->log,0,"writev: %z of %uz",n,vec->size);

处理逻辑:
记录一次writev调用的结果:
实际发送字节数n(格式符%z对应ssize_t)和
请求发送的总字节数vec->size(格式符%uz对应size_t)。

设计意图:%z of %uz的日志格式直观地展示"实际发送 / 请求发送",
例如"writev: 4096 of 8192"表示只发了一半。这在排查部分发送问题时非常有用。


3 成功路径

returnn;

进入条件:n != -1(即writev返回值 >= 0)。

处理逻辑:
直接返回n(实际发送的字节数)。
对于 TCP 套接字,n >= 0且n <= vec->size。
n可能为 0 的极端情况(当所有iov_len均为 0 时),
但 Nginx 的正常路径不会构造空的 iovec。


4 错误路径

if(n==-1){err=ngx_errno;switch(err){caseNGX_EAGAIN:...caseNGX_EINTR:...default:...}}

进入条件:writev返回 -1,表示发生错误。

处理逻辑:
首先通过ngx_errno保存errno的值。
必须在switch之前立即保存——
因为后续的ngx_log_debug0、ngx_connection_error等日志函数内部可能会修改errno
(如调用write到日志文件描述符),
如果在switch中直接使用errno,可能会读到被日志函数覆盖后的错误码。

ngx_errno宏定义(src/os/unix/ngx_errno.h):

#definengx_errnoerrno

在 Unix 平台上直接映射为 POSIXerrno。


4.1 EAGAIN 处理
caseNGX_EAGAIN:ngx_log_debug0(NGX_LOG_DEBUG_EVENT,c->log,err,"writev() not ready");returnNGX_AGAIN;

进入条件:
err == NGX_EAGAIN(即errno == EAGAIN或errno == EWOULDBLOCK)。

处理逻辑:
EAGAIN表示 socket 发送缓冲区已满,数据暂时无法写入。
这是非阻塞 I/O 的正常信号,不是真正的错误。
记录一条调试日志后,返回NGX_AGAIN(-2)。
调用者ngx_writev_chain会将wev->ready置为 0,
然后等待 epoll/kqueue 通知 socket 再次可写。


4.2 EINTR 处理
caseNGX_EINTR:ngx_log_debug0(NGX_LOG_DEBUG_EVENT,c->log,err,"writev() was interrupted");gotoeintr;

进入条件:
err == NGX_EINTR(即writev被信号处理程序中断)。

处理逻辑:
EINTR是 POSIX 信号安全语义的一部分:
当进程收到信号并执行了信号处理函数后,
某些"慢系统调用"(slow system call)会返回 -1 并将errno设为EINTR。
对于writev,此时没有数据被发送,调用者应当重新发起系统调用。
代码通过goto eintr跳回writev调用点,实现自动重试。


4.3 其他错误处理
default:c->write->error=1;ngx_connection_error(c,err,"writev() failed");returnNGX_ERROR;

进入条件:
err不是EAGAIN也不是EINTR——即发生了真正的错误。

处理逻辑:
分两步:

  1. 设置错误标志:
    c->write->error = 1。c->write是连接的写事件对象(ngx_event_t),
    其error位字段标记该事件已进入错误状态。
    上层事件处理循环会检测此标志,触发连接关闭流程。

  2. 记录错误日志:
    调用ngx_connection_error(c, err, "writev() failed"),
    根据错误类型以适当的日志级别记录错误信息。

  3. 返回NGX_ERROR(-1),通知调用者发生了不可恢复的错误。

设计意图:

  • c->write->error = 1在日志记录之前设置,
    这是 Nginx 的错误处理惯例——先标记状态,再记录日志。
    如果日志记录本身触发了错误(极端情况),状态已经正确反映。

  • 返回NGX_ERROR而非直接关闭连接,将关闭决策留给上层——保持职责分离。


相关新闻

  • HarmonyOS 6.1 生态整合实战:服务卡片与“万能卡片”的生态玩法
  • TI HDVPSS数据通路配置:从寄存器解析到画中画实战
  • 嵌入式EMIFA接口与NAND Flash时序配置实战:从理论计算到驱动调试

最新新闻

  • 辛普森案DNA证据争议与程序正义的世纪审判
  • 多头注意力机制解析与Transformer应用实践
  • Codebase-Memory-MCP技术解析:AST知识图谱如何节省99% Token
  • 深入解析EDMA3事件与中断寄存器:从硬件原理到软件实战配置
  • AI工具小白入门组合(限时公开版):内部培训文档首次流出,含3大认知陷阱预警与实操检查表
  • 纪录片思维在技术实践中的应用:从用户行为分析到数据叙事

日新闻

  • AI云原生实战05-金融AI上云最难的不是技术,是“不出事“——TCE银行风控架构拆解
  • 2026年GEOSEO优化公司选型深度测评:五大硬核标准严选,这六家重塑搜索增长新格局 - 品牌前沿专家
  • **核验!2026年7月卡地亚香港**售后网点地址及服务电话公告 - 卡地亚服务中心

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号