readv和writev的工作流程。使用readv和writev而不是使用read和write有什么好处?

时间:2018-03-09 07:14:32

标签: c system-calls

我正在尝试使用readv()从文件中获取数据。但它总是打印垃圾字符。我试图为iovec.iov_base分配空间,但即使它显示垃圾字符。我甚至怀疑为什么我应该使用readv而不是使用更简单的read函数。我需要了解有关readv和writev的所有信息。我对他们很困惑。

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/uio.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #define MAX 50000
    int main()
    {
        struct iovec data[2];
        int i=0,fd;
        for(i=0; i<3 ; i++ )  {
            data[i].iov_len=MAX;
            data[i].iov_base=(char*) malloc(MAX); //if this line is in comment, segmentation fault will occur. 
            /* data[i].iov_base=(char*) malloc(0); //This is also working ?*/
        }
        fd=open("/tmp/test",O_RDWR);
        if(fd==-1){
            printf("can't open the input file\n");
            return 1;
        }
        readv(fd,data,3);
        for(i=0; i<2 ; i++ )  {
            printf("((%s))\n",(char*)data[i].iov_base);
        }
    }

1 个答案:

答案 0 :(得分:1)

当您使用文件描述符时,您需要使用POSIX https://perldoc.perl.org/IO/Socket.htmlreadv()函数('scatter read'和'gather write' - 另请参阅writev()上的Wikipedia) group从不同(非连续)内存位置的集合读取或写入,但您希望通过单个函数调用完成读取或写入。

例如,我有一个程序需要记录一些控制数据和一些二进制数据的十六进制转储,但它希望确保其写入是原子的。所以,我有这样的功能:

static void log_message(int log_fd, const char *elapsed, const char *tag, const char *buffer, ssize_t nbytes)
{
    char hdrbuff[64];
    struct iovec vector[3];
    const char *data = format_image(buffer, nbytes);

    snprintf(hdrbuff, sizeof(hdrbuff), "%s %s %6ld\n", elapsed, tag, (long)nbytes);

    vector[0].iov_base = hdrbuff;
    vector[0].iov_len  = strlen(hdrbuff);
    vector[1].iov_base = CONST_CAST(char *, data);
    vector[1].iov_len  = strlen(data);
    vector[2].iov_base = "\n";
    vector[2].iov_len  = 1;
    if (writev(log_fd, vector, 3) <= 0)
        err_syserr("Failed to write log entry (%s: %ld)\n", tag, (long)nbytes);
}

需要编写换行符是一种轻微的麻烦,但format_image()函数无法添加杂散换行符。 (它是在其他地方使用的库函数,如果它添加了额外的换行符,那么其他用途就会被破坏。)但是,writev()允许我在不更改库函数的情况下编写所有内容,并最大化赢得的机会不要在文件上进行任何交错。 (在上下文中,第二个进程使用相同的日志文件和相同的打开文件描述,但协议是半双工的,因此临时重叠的可能性很小。但是,使用分散/聚集I / O可以最大限度地减少机会问题。)

我没有使用我能记住的readv()的示例,但是当您知道有多个固定大小的数据块可以读入非连续的内存位置时,您就会使用它。 / p>