C/C++之readv/writev

前言

在使用socket进程间通信时,如何完成这样一个功能呢:一个进程向另一个进程发送一个cmd,同时发送把这个cmd所携带的参数也发送出去?

在linux上进行开发时,我们经常会使用read和write进行socket通信,但是上面这个功能如果使用read和write来完成,则需要多次调用两个函数来最终达到这样的需求,这样肯定会造成性能的损失,那么还有可以直接实现这个需求的函数吗,是的,writev和readv就可以实现这样一个功能。

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

ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
  • fd表示打开的文件描述符,iov表示指向iovec结构体数组的结构体指针,iovcnt表示
    结构体数组中元素的个数
  • 成功时,返回值为从缓存区中读出或写入缓存区的字节数
    失败时返回-1并设置相应的errno
  1. 这两个函数类似于read和write,不过readv和writev允许单个系统调用读入到或写出自一个或多个缓冲区。这些操作分别称为分散读(scatter read)和集中写(gather write),因为来自读操作的输入数据被分散到多个应用缓冲区中,而来自应用缓冲区的输出数据则被集中提供给单个写操作。

  2. iovec结构数组中元素的数目存在某个限制(IOV_MAX),具体取决于实现。POSIX要求在头文件<sys/uio.h>中定义IOV_MAX常值,而且其值至少为16。

  3. readv和writev这两个函数可以用于任何描述字,而不仅限于套接口。另外,writev是一个原子操作,意味着对于一个基于记录的协议(例如UDP)而言,一次writev调用只产生单个UDP数据报。

writev

创建1个文件f3

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/uio.h>
int main(int argc,char *argv[])
{
        int fd3;
        ssize_t size;
        char buf1[9]="12345678",buf2[7]="123456";
        struct iovec iov[2];

        fd3=open(argv[1],O_RDWR);

        iov[0].iov_base=buf1;
        iov[0].iov_len=sizeof(buf1);
        iov[1].iov_base=buf2;
        iov[1].iov_len=sizeof(buf2);
        size=writev(fd3,iov,2);
        printf("%s size is :%d\n",argv[1],size);
        close(fd1);
        close(fd2);
        close(fd3);
}

编译执行

VM-4-10-ubuntu:~/WorkSpace/TestC$ ./testwritev f3
f3 size is :16

可见f3内存放了16个字节的数据

readv

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/uio.h>
int main(int argc,char *argv[])
{
        int fd3;

        fd3=open(argv[1],O_RDWR);

        char buf3[9]={0}, buf4[7]={0};
        struct iovec iov2[2];
        iov2[0].iov_base= buf3;
        iov2[0].iov_len=sizeof(buf3);
        iov2[1].iov_base = buf4;
        iov2[1].iov_len = sizeof(buf4);
        ssize_t ret = readv(fd3,iov2,2);
        printf("ret=%d,read data from fd3, buf3=%s, buf4=%s\n",ret, buf3, buf4);
        close(fd3);
}

编译执行

:~/WorkSpace/TestC$ ./testreadv f3
ret=18,read data from fd3, buf3=12345678, buf4=123456

可见,readv将读出的数据按照指定的长度分配到了两个不同的内存buf3和buf4中。

需要注意的是,如果buf1中的数据末尾没有"\0",那么在存储到fd3中后,两段数据之间是没有分割的,那么在buf1和buf2就被存储在了一块连续的内存中,在使用readv读取时,buf虽然指定了长度,但是由于存储在fd3中的数据是连续的,那么会将buf2所表示的数据一并读取到buf3中,这是应该避免的。

writev的特点:

writev允许处理非连续的数据块。也就是说,缓冲区可以逐个单独分配,不用是一块连续的较大的地址空间。

writev 的I/O是“原子的”。例如,如果你执行一个writev操作,所有数据将在一个连续操作中被写入,不会被中断。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael.Scofield

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值