pwritev系统调用及示例

pwritev 函数

1. 函数介绍

pwritev 是 pwrite 的聚集写入版本,它允许一次性将多个不连续缓冲区中的数据写入到文件的指定位置。这是分散/聚集I/O操作的写入部分。

2. 函数原型

#define _GNU_SOURCE
#include <sys/uio.h>
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);

3. 功能

将由 iov 描述的多个缓冲区中的数据写入到文件描述符 fd 指定的文件中,从 offset 位置开始写入。该操作不会改变文件的当前读写位置。

4. 参数

  • int fd: 文件描述符,必须是已打开的文件
  • *const struct iovec iov: iovec结构体数组,描述多个缓冲区
  • int iovcnt: iov数组中的元素个数
  • off_t offset: 文件中的偏移量(从文件开始处计算)

5. 返回值

  • 成功: 返回实际写入的总字节数
  • 失败: 返回-1,并设置errno

6. 相似函数,或关联函数

  • writev: 基本的聚集写入函数
  • pwrite: 单缓冲区定位写入函数
  • preadv: 对应的读取函数

7. 示例代码

#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/**
 * 使用pwritev进行聚集写入
 */
int demo_pwritev_basic() {
    int fd;
    struct iovec iov[3];
    ssize_t total_bytes;
    
    // 准备要写入的数据
    char data1[] = "First part of the message\n";
    char data2[] = "Second part with more content ";
    char data3[] = "and final part.\n";
    
    printf("=== pwritev 基本使用示例 ===\n");
    printf("准备写入的数据:\n");
    printf("数据1: %s", data1);
    printf("数据2: %s", data2);
    printf("数据3: %s", data3);
    
    // 创建测试文件
    fd = open("test_pwritev.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1) {
        perror("创建测试文件失败");
        return -1;
    }
    
    // 设置iovec数组
    iov[0].iov_base = data1;
    iov[0].iov_len = strlen(data1);
    iov[1].iov_base = data2;
    iov[1].iov_len = strlen(data2);
    iov[2].iov_base = data3;
    iov[2].iov_len = strlen(data3);
    
    // 使用pwritev写入数据
    total_bytes = pwritev(fd, iov, 3, 0);
    if (total_bytes == -1) {
        perror("pwritev 失败");
        close(fd);
        return -1;
    }
    
    printf("\npwritev 写入了 %zd 字节到文件\n", total_bytes);
    
    // 读取并验证写入的数据
    char buffer[256];
    lseek(fd, 0, SEEK_SET);
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("\n文件内容验证:\n%s", buffer);
    }
    
    close(fd);
    unlink("test_pwritev.txt");
    return 0;
}

/**
 * 演示pwritev写入HTTP响应头
 */
int demo_pwritev_http_response() {
    int fd;
    struct iovec iov[4];
    ssize_t total_bytes;
    
    printf("\n=== pwritev HTTP响应示例 ===\n");
    
    // HTTP响应的各个部分
    char status_line[] = "HTTP/1.1 200 OK\r\n";
    char headers[] = "Content-Type: text/html\r\n"
                     "Content-Length: 25\r\n"
                     "Connection: close\r\n";
    char separator[] = "\r\n";
    char body[] = "<html><body>Hello</body></html>";
    
    // 创建测试文件
    fd = open("http_response.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1) {
        perror("创建HTTP响应文件失败");
        return -1;
    }
    
    // 设置iovec数组
    iov[0].iov_base = status_line;
    iov[0].iov_len = strlen(status_line);
    iov[1].iov_base = headers;
    iov[1].iov_len = strlen(headers);
    iov[2].iov_base = separator;
    iov[2].iov_len = strlen(separator);
    iov[3].iov_base = body;
    iov[3].iov_len = strlen(body);
    
    // 一次性写入完整的HTTP响应
    total_bytes = pwritev(fd, iov, 4, 0);
    if (total_bytes == -1) {
        perror("pwritev 写入HTTP响应失败");
        close(fd);
        return -1;
    }
    
    printf("成功写入HTTP响应,共 %zd 字节\n", total_bytes);
    
    // 显示生成的HTTP响应
    char buffer[512];
    lseek(fd, 0, SEEK_SET);
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("\n生成的HTTP响应:\n%s", buffer);
    }
    
    close(fd);
    unlink("http_response.txt");
    return 0;
}

int main() {
    if (demo_pwritev_basic() == 0) {
        demo_pwritev_http_response();
        printf("\n=== pwritev 使用总结 ===\n");
        printf("优点:一次系统调用写入多个缓冲区,提高效率\n");
        printf("适用场景:网络协议数据发送,日志记录,配置文件更新\n");
    }
    return 0;
}

pwritev系统调用及示例-CSDN博客

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注