这几天,写服务器代码的过程当中,顺便把以前看apue的代码拿来记录下,以便以后找起来方便一些。
readv和writev函数用于在一次函数操作中读、写多个非连续的缓冲区。这在写http一类的协议头的时候感觉很方便。例如用writev把多个协议头用着一个函数写给fd。下面是我的一个例子:
#include
#include
#include
#include
#include
#include
const char str1[] = "hello\n";
const char str2[] = "world,fuck!!\n";
void main(void)
{
int ret, len;
char temp;
char readbuf1[30];
char readbuf2[30];
struct iovec iov[2];
iov[0].iov_base = str1;
iov[0].iov_len = strlen(str1);
iov[1].iov_base = str2;
iov[1].iov_len = strlen(str2);
len = iov[1].iov_len + iov[0].iov_len;
int fd = open("testfile", O_RDWR | O_CREAT);
if(fd < 0)
{
printf("open file failed\n");
exit(1);
}
ret = writev(fd, &iov[0], 2);
if(ret != len)
{
printf("writev failed\n");
close(fd);
exit(1);
}
fd = open("testfile", O_RDONLY);
if(fd < 0)
{
printf("open file failed\n");
exit(1);
}
printf("test writev:\n");
while(read(fd, &temp, 1) != 0)
write(STDOUT_FILENO, &temp, 1);
close(fd);
printf("sleep for a few seconds\n");
sleep(3);
printf("test readv:\n");
iov[0].iov_base = readbuf1;
iov[0].iov_len = 30;
iov[1].iov_base = readbuf2;
iov[1].iov_len = 30;
fd = open("testfile", O_RDONLY);
if(fd < 0)
{
printf("open file failed\n");
exit(1);
}
memset(readbuf1, 0, 30);
memset(readbuf2, 0, 30);
ret = readv(fd, &iov[0], 2);
if(ret != len)
{
printf("readv failed\n");
close(fd);
exit(1);
}
close(fd);
printf("readbuf1: %s\n", readbuf1);
printf("readbuf2: %s\n", readbuf2);
exit(0);
}
上面是执行结果,这里注意从文件读出来的时候,是把第一个缓冲区填满后,才往第二个缓冲区写入。
上面的执行结果可以看出,第一个没有写满,所以第二个内容是空的,另外缓冲区的大小在读的时候是根据iov[0]和iov[1]的iov_len字段来确定的。
即使缓冲区很大,但是读的时候读多少由len确定。
如将上面代码中的
iov[0].iov_base = readbuf1;
iov[0].iov_len = 30;
中的30改成3,则执行情况如下:
另外,apue1,389页,有下面描述:
对于少量数据,使用writev的固定开销大于得益,随着需要复制数据的增加,程序中复制数据的开销也会增多,此时,writev这种替代方法就会有更大的吸引力。
阅读(5201) | 评论(0) | 转发(0) |