CppGuide社区 CppGuide社区
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 🔥最新谷歌C++风格指南(含C++17/20)
  • 🔥C++17详解
  • 🔥C++20完全指南
  • 🔥C++23快速入门
  • C++语言面试问题集锦
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • 🔥C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 🔥从零用C语言写一个Redis
  • 🔥Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 🔥使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
Rust编程指南
  • SQL零基础指南
  • MySQL开发与调试指南
GitHub (opens new window)
  • 第1章高频C++11重难点知识解析

  • 第2章Linux GDB高级调试指南

  • 第3章C++多线程编程从入门到进阶

  • 第4章C++网络编程重难点解析

    • 4.1 学习网络编程,你应该掌握哪些 socket 函数
    • 4.2 TCP 网络通信的基本流程
    • 4.3 设计跨平台网络通信库时需要注意的一些 socket 函数用法
    • 4.4 bind 函数重难点分析
    • 4.5 select 函数用法和原理
    • 4.6 socket 的阻塞模式和非阻塞模式
    • 4.7 发送 0 字节的数据是什么效果?
    • 4.8 connect 函数在阻塞和非阻塞模式下的行为
    • 4.9 连接时顺便接收第一组数据
    • 4.10 如何获取当前 socket 对应的接收缓冲区中有多少数据可读
    • 4.11 Linux EINTR 错误码
    • 4.12 Linux SIGPIPE 信号
    • 4.13 Linux poll 函数用法
    • 4.14 Linux epoll 模型
    • 4.15 高效的 readv 和 writev 函数
    • 4.16 主机字节序和网络字节序
    • 4.17 域名解析 API 介绍
  • 第5章网络通信故障排查常用命令

  • 第6章高性能网络通信协议设计精要

  • 第7章高性能服务结构设计

  • 第8章Redis 网络通信模块源码分析

  • 第9章后端服务重要模块设计探索

  • C++后端开发进阶
  • 第4章C++网络编程重难点解析
zhangxf
2023-04-05

4.15 高效的 readv 和 writev 函数

在实际开发种,高性能服务有一条尽量减少系统调用的原则。对于一个文件描述符(file descriptor,fd,例如文件指针、套接字类型)的 read 或者 write,都是系统调用。有时候我们会遇到通过一个文件描述对应的文件或套接字上将数据读到多个缓冲区中去,或者将多个缓冲区中的数据同时写入一个文件描述符对应的文件或者套接字中。当然,你可以通过多次调用 read 或者 write,挨个操作每个缓冲区。Linux 系统提供了一组 readv 和 writev 系列函数来完成上述工作。这个系列函数的签名如下:

#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);

ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
1
2
3
4
5
6
7
8
9

参数 fd 和 offset 的含义都是不言自明的。参数 iov 是一个 struct iovec 数组,参数 iovcnt 是该数组元素的个数。函数 readv 和 preadv 调用成功返回总读取字节数,函数 writev 和 pwritev 调用成功返回总写入字节数,函数调用失败均返回 -1。

struct iovec 定义如下:

struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};
1
2
3
4

字段 iov_base 是存放数据缓冲区的地址,字段 iov_len 是缓冲区的长度。

我们以 writev 函数为例来演示其用法,假设现在我们需要将 3 段数据同时写入一个 CSV 文件中,第一段数据是 CSV 的文件头信息,第二段和第三段是两只股票信息。示例代码如下:

char* headerInfo = "timestamp,symbol,side,volume,price\n";
char* firstSymbolInfo = "2014-12-12D06:53:11.127838000,600358,Buy,347,3.48\n";
char* secondSymbolInfo = "2014-12-12D06:53:11.127838000,600359,Buy,251,4.99\n";

struct iovec iov[3];
iov[0].iov_base = headerInfo;
iov[0].iov_len = strlen(headerInfo);
iov[1].iov_base = firstSymbolInfo;
iov[1].iov_len = strlen(firstSymbolInfo);
iov[2].iov_base = secondSymbolInfo;
iov[2].iov_len = strlen(secondSymbolInfo);

//fpCSV 为打开的CSV文件句柄
ssize_t nwritten = writev(fpCSV, iov, 2);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

为了提高程序执行效率,读者可能会在很多 C/C++ 网络库中见到 readv 和 writev 函数的身影。

上次更新: 2025/04/01, 20:53:14
4.14 Linux epoll 模型
4.16 主机字节序和网络字节序

← 4.14 Linux epoll 模型 4.16 主机字节序和网络字节序→

最近更新
01
第二章 关键字static及其不同用法
03-27
02
第一章 auto与类型推导
03-27
03
C++语言面试问题集锦 目录与说明
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式