一、簡介
structiovec是一個在C語言中常用的數據結構,用於實現分散/聚集I/O。該結構體將多個緩衝區封裝成一個向量,使得可以一次性地將向量中的多個緩衝區內容寫入或從文件中讀取。
structiovec由兩個成員變數組成:一個指針(iov_base)和一個長度(iov_len)。iov_base指向一個緩衝區的地址,iov_len表示此緩衝區的長度。對於每個向量,可以指定多個緩衝區,每個緩衝區由一個struct iovec結構體來表示。
使用structiovec的好處包括:簡化代碼、提高效率、兼容性強,因此值得我們在實踐中深入了解。
二、聚集I/O
聚集I/O用於將多個緩衝區中的數據讀取或寫入到單個文件中。使用聚集I/O的好處在於可以減少系統調用的次數,提高效率。structiovec中的成員變數iov_base指向一個緩衝區的地址,iov_len表示此緩衝區的長度。對於每個向量,可以指定多個緩衝區,每個緩衝區由一個struct iovec結構體來表示。
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
int main()
{
struct iovec iov[3];
char buf1[] = "Data from";
char buf2[] = " multiple";
char buf3[] = " buffers.";
iov[0].iov_base = buf1;
iov[0].iov_len = strlen(buf1);
iov[1].iov_base = buf2;
iov[1].iov_len = strlen(buf2);
iov[2].iov_base = buf3;
iov[2].iov_len = strlen(buf3);
ssize_t nwritten = writev(STDOUT_FILENO, iov, 3);
printf("%d bytes written\n", nwritten);
return 0;
}
在上述代碼中,我們定義了3個緩衝區buf1、buf2、buf3,然後將它們封裝進一個向量iov中,並使用writev函數將向量中的所有緩衝區內容一次性地寫入STDOUT_FILENO中。
三、分散I/O
分散I/O用於從單個文件中讀取數據到多個緩衝區中。使用分散I/O的好處在於可以減少系統調用的次數,提高效率。structiovec中的成員變數iov_base指向一個緩衝區的地址,iov_len表示此緩衝區的長度。對於每個向量,可以指定多個緩衝區,每個緩衝區由一個struct iovec結構體來表示。
#include <stdio.h>
#include <sys/uio.h>
int main()
{
struct iovec iov[3];
char buf1[5];
char buf2[5];
char buf3[5];
iov[0].iov_base = buf1;
iov[0].iov_len = sizeof(buf1);
iov[1].iov_base = buf2;
iov[1].iov_len = sizeof(buf2);
iov[2].iov_base = buf3;
iov[2].iov_len = sizeof(buf3);
ssize_t nread = readv(STDIN_FILENO, iov, 3);
printf("%d bytes read: %s%s%s\n", nread, buf1, buf2, buf3);
return 0;
}
在上述代碼中,我們定義了3個緩衝區buf1、buf2、buf3,並將它們封裝進一個向量iov中,然後使用readv函數將STDIN_FILENO中的內容一次性地讀取到各個緩衝區中。
四、使用結構體數組來實現分散/聚集I/O
可以使用結構體數組來實現分散/聚集I/O功能。這種方法的好處在於:可以預定義一組緩衝區並使用它們來讀取和寫入數據(常用於網路編程中)。
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
struct myiovec {
char *iov_base;
size_t iov_len;
};
int main()
{
struct myiovec iov[3];
char buf1[] = "Data from";
char buf2[] = " multiple";
char buf3[] = " buffers.";
iov[0].iov_base = buf1;
iov[0].iov_len = strlen(buf1);
iov[1].iov_base = buf2;
iov[1].iov_len = strlen(buf2);
iov[2].iov_base = buf3;
iov[2].iov_len = strlen(buf3);
ssize_t nwritten = writev(STDOUT_FILENO, (const struct iovec *)iov, 3);
printf("%d bytes written\n", nwritten);
return 0;
}
在上述代碼中,我們定義了一個包含3個元素的結構體數組iov,其中每個元素包含一個緩衝區的地址和它的長度。最後,我們使用writev函數將結構體數組中的所有緩衝區內容一次性地寫入STDOUT_FILENO中。
五、使用bvec來進行流取向的I/O
分散/聚集I/O用於單個文件中的讀寫,而流取向的I/O用於網路編程中,實現了分散/聚集I/O在一個套接字上傳輸的功能。
在Linux環境下,定義了一個bvec結構體來實現流取向的I/O功能。這個結構體的成員變數包括:bv_page、bv_len和bv_offset。其中,bv_page指向一個內存頁面,bv_len表示該頁面的長度,bv_offset表示該頁面的偏移量。這些頁面是用來緩存網卡收發的數據的。
#include <linux/types.h>
#include <asm/scatterlist.h>
#include <linux/highmem.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
{
struct kvec iov;
struct sock_iocb iocb;
struct iov_iter iter;
struct sg_table sg;
struct scatterlist *sgl;
unsigned int sgl_nents, offset;
int size;
sgl_nents = skb_to_sgvec(msg->msg_iter.bvec.vec.bv_page,
msg->msg_iter.bvec.vec.bv_len, 0, &sg, 1);
sgl = sg.sgl;
offset = 0;
iov.iov_len = len;
iov_iter_init(&iter, WRITE, &iov, 1, len);
while (offset < len) {
size = kernel_sendmsg(sock, msg, &iov, 1, len);
if (size < 0)
return size;
iov_iter_advance(&iter, size);
offset += size;
}
return offset;
}
在上述代碼中,我們定義了一個sock_sendmsg函數來實現流取向的I/O。其中,sgl_nents用於設置sgl數組的長度,sgl數組包含指向多個頁面的指針。通過在sgl數組中設置多個頁面的指針,我們可以實現多個緩衝區的讀取和寫入。
六、結論
使用structiovec可以極大地簡化代碼,並提高程序的效率。聚集I/O用於將多個緩衝區中的數據讀取或寫入到單個文件中,而使用分散I/O可以從單個文件中讀取數據到多個緩衝區中。在網路編程中,我們可以使用bvec結構體來實現流取向的I/O功能。實踐中請根據自己的需求選擇合適的方法。
原創文章,作者:ADJKT,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/368703.html
微信掃一掃
支付寶掃一掃