Linux IO函式的使用和區別

2022-03-17 08:27:17 字數 3814 閱讀 5860

linux系統中的io函式主要有read、write、recv、send、recvmsg、sendmsg、readv、writev,本篇主要介紹他們的使用以及區別。

read函式:

#include 

ssize_t read(int fd,void *buf,size_t count);

read函式從檔案描述符fd對應的檔案中,讀取count位元組,放在buf緩衝區。如果count為0,read返回為0,不進行其他操作;如果count的值大於ssize_max,結果不能預料。在讀取成功的時候,檔案對應的讀取位置指標,,向後移動位置,大小為成功讀取的位元組數。

如果read執行成功,訪回讀取的位元組數;當返回為-1時候,讀取函式有錯誤發生。如果已經達到檔案的末尾,返回0;其中,ssize資料型別是不同於int、long型別,它是符號數,具體實現時,可能是int,也可能是long。

write函式:

#include 

ssize_t write(int fd,const

void *buf,size_t count);

引數含義與read類似。

recv函式:

#include 

#include

ssize_t recv(int s,void *buf,size_t len,int flags);

recv函式用於接受資料,該函式從套接字s中接收資料放到緩衝區buf中,buf長度為len,操作的方式由flags指定,第乙個引數s是套接字檔案描述符,它是由系統呼叫socket函式返回。第二個引數buf是乙個指標,指向接收網路的緩衝區。第三個引數len表示緩衝區的大小,以位元組為單位。第四個引數flags用於設定接收資料的方式:

recv()函式flasgs的值及含義

msg_dontwait

非阻塞,立即返回,不等待

msg_errqueue

錯誤訊息從套接字錯誤佇列中接收

msg_oob

接收外部資料

msg_peek  

檢視資料,不進行資料緩衝區的清空

msg_trunc

返回所有資料,即使指定的緩衝區過小

msg_waitall

等待所有訊息

msg_dontwait:這個標誌將單個io操作設為非阻塞,而不需要在套接字上開啟非阻塞標誌,執行io,然後關閉非阻塞標誌。

msg_errqueue:該錯誤的傳輸依賴於所使用的協議。

msg_oob:這個標誌可以接收帶外的資料,而不是接收一般資料。

msg_peek:這標誌檢視可讀的資料,在recv函式執行後,核心不會將這些資料丟棄。

msg_trunc:在接收資料後,如果使用者的緩衝區大小不足以完全複製緩衝區裡的資料,則將資料截掉,僅靠複製使用者緩衝區大小的資料,其他的資料將丟棄。

msg_waitall:告訴核心在沒有讀到請求的位元組數之前不要讀操作返回。如果系統支援這個標誌,可以去掉readn()函式而用下面的替代:

#define readn(fd,ptr,n) recv(fd,ptr,n,msg_waitall).

即使設定了msg_waitall,如果發生以下情況:a撲捉乙個訊號;b連線終止;c在套接字上發生錯誤,這個函式返回的位元組數仍然比請求的少。

當指定msg_waitall標誌時,函式會複製與使用者指定的長度相等的資料。如果核心中的資料不能滿足要求,會一直等待到資料足夠的時候才返回。

函式recv()的返回值是成功接收到的位元組數,當返回值為-1時錯誤發生。

recv函式errno的值及含義

eagain

套接字定義為非阻塞,而操作採用了阻塞方式;或者定義了超時時間到了,而沒有接收到資料

ebadf

引數s不是合法的描述符

econnrefused

遠端主機不允許此操作

efault

接收緩衝區的指標,在此程序之外

eintr

接收到中斷訊號

einval

傳遞了不合法的引數

enotconn

套接字s表示流式套接字,此套接字沒有連線

enotsock

引數不是套接字描述符

recv()通常用於tcp,udp使用recvfrom函式接收資料,當然在資料報套接字繫結了位址和埠後,也可以使用recv函式接收資料。

recv()從核心的接收緩衝區中複製資料到使用者指定的緩衝區,當核心中的資料比指定的緩衝區小時,一般情況下(沒有採用msg_waitall標誌)會複製緩衝區中的所有資料到使用者緩衝區,並返回資料的長度。當核心中的資料比指定的緩衝區多時,會將使用者指定的長度的接收緩衝區中的資料複製到使用者指定位址,其餘的資料需要下次呼叫接收函式時再複製,核心在複製使用者指定的資料後,會銷毀已經複製完畢的資料,並進行調整。

send函式:

#include #include 

ssize_t send(

int s,const

void*buf,size_t len,int flags);

send函式將緩衝區buf中的大小為len的資料,通過套接字檔案描述符s按照flasg指定的方式發生出去(其中的含義與recv()中一致),它的返回值是成功發生的位元組數。

由於使用者緩衝區buf中的資料通過send傳送,不一定能夠全部傳送出去,所以要檢查send()返回值。當send()的返回值小於len時,表面緩衝區中仍有部分資料沒有傳送成功,這時需要重新傳送剩餘部分的資料。通常的剩餘資料傳送方式是對原來的buf中的資料位置進行偏移,偏移的大小為已經傳送成功的位元組數。

當send()返回-1時,就錯誤了。

函式send()只能用於套接字處於連線狀態的描述符,之前必須用connect()函式或者其他函式進行連線。對於send和write之間的差別是表示傳送方式flag,當flag為0時,send()和write()完全一樣的,且send(s,buf,len,flags)和sendto(s,buf,len,flags,null,0)是等價的。

readv函式:

#include ssize_t readv(

int s,const

struct iovec*vector,int count);

read()可以接收多個緩衝區的資料。readv函式從套接字描述符s中讀取count塊的資料放在緩衝區向量vector中。返回值為成功接收到的資料的位元組數,當-1時,錯誤發生。

其中的引數vector為乙個向量的指標,結構struct iover在檔案定義:

1

struct

iovec

2

在呼叫readv的時候必須指定iovec的iov_len長度,將值放在iov_len中。引數vector指向一塊結構vector的記憶體,大小count定。如下圖,其中陰影部分是需要設定的。

writev函式:

#include ssize_t writev(

int s,const

struct iovec*vector,int

count);

//// 是不是覺得和readv一樣

總結:下表總結了各個函式的區別、特點:o標記的為具備此種屬性

Linux IO的水平觸發和邊緣觸發的區別

linux io的水平觸發和邊緣觸發的區別 在linux的io多路復用中有水平觸發,邊緣觸發兩種模式,這兩種模式的區別如下 水平觸發 如果檔案描述符已經就緒可以非阻塞的執行io操作了,此時會觸發通知.允許在任意時刻重複檢測io的狀態.select,poll就屬於水平觸發.邊緣觸發 如果檔案描述符自上...

檔案操作函式的使用和區別

一 fopen 與 fclose 函式的使用 fopen 函式用於開啟乙個檔案 函式定義 file fopen const char filename,const char mode fopen 的返回值是乙個檔案指標,file 是在stdio.h中定義的結構體型別,封裝了與檔案相關的資訊 stru...

Lua中使用 和 呼叫函式的區別

tb.print和tb print的含義略微不同,呼叫函式會多傳遞進去乙個self進去,差不多相當於oop裡面的成員函式呼叫.但是和oop裡面成程式設計客棧員函式 非成員函式不同的是,lua裡面的程式設計客棧非成員函式.呼叫,他不是靜態的.tb物件有乙個print function成員,當tb是ni...