日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 高级i o函数,高级I/O函数

發布時間:2025/3/11 linux 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 高级i o函数,高级I/O函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對于socket,最基本的輸入輸出函數就是,read和write。它們最基本,同樣功能也是最少的。Unix中有幾個函數是read/write的變種,在基本的輸入輸出功能上,還增加了一些非常使用的功能和特性,它們是:recv/send、readv/writev和recvmsg/sendmsg。

1、socket超時的實現

一般來說,要在對socket的I/O操作實現超時,有3種方式:

·注冊SIGALRM信號的處理函數,然后調用alrm,則若對socket的I/O操作阻塞時間大于alrm注冊的時間,則在alrm時間到時會阻塞會被SIGALRM打斷。這樣做有個缺點,就是alrm的調用會影響到同一進程的其他alrm調用。某些系統中,系統調用被信號打斷后,會自動重新調用,在這種系統中可以使用setlongjmp/siglongjmp來跳出。

·使用SO_RCVTIMEO/SO_SNDTIMEO選項。注意,并不是所有的系統都支持這兩個選項。

·用select代替read/write。

前面兩種方式只對socket進行輸入/輸出有效,而最后一種除了輸入/輸出以外,還對connect有效(socket必須處于nonblocking模式下)。

2、recv/send

函數原型:

#include

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);

Both return: number of bytes read or written if OK, –1 on error

可以看到,前3個參數和read/write是一樣的,很好理解。最后一個flag參數的值可以是一下幾個常量中的一個或多個的或:

·MSG_DONTROUTE 適用于send,表示此次發送的數據包不經過系統的路由過程,直接發送。

·MSG_DOWAIT 適用于recv/send,表示此次操作采用非阻塞方式(不一定所有的系統都支持此項)。

·MSG_OOB 適用于recv/send,表示發送或接收“out-of-band data”(只能發送1個字節的out-of-band data)。

·MSG_PEEK 適用于recv,表示此次讀取的是緩存中數據的副本。

·MSG_WAITALL 適用于recv,表示調用將直接阻塞知道指定的指定的字節數被讀出(若中途遇到EOF或出錯,則也會少于指定字節數)。

2、readv/writev

原型:#include

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

ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);

Both return: number of bytes read or written, –1 on error

這兩個函數名字和read/write只多一個字母'v',功能更強大。readv可以將數據讀入到多個buffer中,而writev可以將多個buffer的數據輸出。iov指向一個iovec的數組,iovcnt為數組大小(linux中最大為1024)。

iovec結構如下:struct iovec {

void *iov_base; /* starting address of buffer */

size_t iov_len; /* size of buffer */

};

iov_base指向buffer的起始地址,iov_len為buffer的大小。

3、recvmsg/sendmsg

這對函數可以說是socket輸入/輸出的“萬金油”,它們可以替代之前提到過的輸入/輸出函數。原型如下:#include

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

Both return: number of bytes read or written if OK, –1 on error

大部分重要的都放在msg指向的msghdr中:struct msghdr {

void *msg_name; /* protocol address */

socklen_t msg_namelen; /* size of protocol address */

struct iovec *msg_iov; /* scatter/gather array */

int msg_iovlen; /* # elements in msg_iov */

void *msg_control; /* ancillary data (cmsghdr struct) */

socklen_t msg_controllen; /* length of ancillary data */

int msg_flags; /* flags returned by recvmsg() */

};

msg_name指向相應的socket地址,msg_namelen為地址大小,這兩個成員僅在socket未連接的情況下使用(需設置IP_RECVDSTADDR),對于已連接的socket(如TCP和已連接的UDP),msg_name應置為NULL,msg_namelen為0。在使用recvmsg時,msg_namelen是值-結果類型。

msg_iov與msg_iovlen和readv/writev表示的意義一樣。

msg_flags僅對recvmsg有用,當recvmsg調用時,將flags賦值給msg_flags,然后內核按照msg_flags進行操作,返回時將更新(有可能)后的flags通過這個值返回;sendmsg僅使用flags。

附表,flag總結

msg_control成員很重要,下一節將詳細分析;msg_controllen為msg_control大小。

4、輔助數據

輔助數據是指msghdr中的msg_control和msg_controllen成員,它們又稱謂“控制信息”。在某些情況下,這些信息是非常有用的。

附表,輔助數據總結(直接截圖,湊活著看)

輔助數據可以包含多條信息,每條信息存放在cmsghdr的結構中:

struct cmsghdr {

socklen_t cmsg_len; /* length in bytes, including this structure */

int cmsg_level; /* originating protocol */

int cmsg_type; /* protocol-specific type */

/* followed by unsigned char cmsg_data[] */

};

注意,數據區cmsg_data是可變的,按需求分配。

在處理cmsghdr時,有5個實用的宏:#include

#include /* for ALIGN macro on many implementations */

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr) ;

#Returns: pointer to first cmsghdr structure or NULL if no ancillary data

struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr) ;

#Returns: pointer to next cmsghdr structure or NULL if no more ancillary data objects

unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr) ;

#Returns: pointer to first byte of data associated with cmsghdr structure

unsigned int CMSG_LEN(unsigned int length) ;

#Returns: value to store in cmsg_len given the amount of data

unsigned int CMSG_SPACE(unsigned int length) ;

#Returns: total size of an ancillary data object given the amount of data

圖例:

代碼片段:

struct msghdr msg;

struct cmsghdr *cmsgptr;

/* fill in msg structure */

/* call recvmsg() */

for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;

cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {

if (cmsgptr->cmsg_level == ... &&

cmsgptr->cmsg_type == ... ) {

u_char *ptr;

ptr = CMSG_DATA(cmsgptr);

/* process data pointed to by ptr */

}

}

5、如何得知當前緩沖區中有多少數據?

使用MSG_PEEK即可,這樣可以獲取緩沖區數據的副本,而不是“消耗”,副本的大小即為當前緩沖區中的數據量。需注意的是,網卡每時每刻都有可能收到數據,因此緩沖區的數據量是一直在變化的。

6、socket I/O與標準I/O

之前提到的函數(read/write、recv/send等)都是系統調用,除了系統調用之外,還可以使用標準I/O庫操作socket。標準I/O庫自帶緩沖機制,同時考慮了一些細節,這給使用者帶來一定的方便。但是,方便的同時,它帶來了新的問題,這些問題的根源就是緩沖機制!避免一些“奇怪”問題的建議就是,不要使用標準I/O庫來處理socket。(見unpv13e 14.8)

總結

以上是生活随笔為你收集整理的linux 高级i o函数,高级I/O函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。