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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux系统函数read()/write()/pread()/pwrite()的区别

發布時間:2024/1/23 linux 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统函数read()/write()/pread()/pwrite()的区别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載地址:https://blog.csdn.net/u013525455/article/details/52661313

在Linux和UNIX中有很多的輸入輸出函數,有時真是讓想跟它攀點關系的菜鳥們束手無策。先來看看都有哪些函數,通過解析與總結,看看能不能讓大家能這些函數有個理性的認識,哦,原來是這么回事,也就算我沒白花這份閑。

內核文件I/O->標準庫I/O->高級I/O->IPC中

1.?????????read()/write();

2.?????????pread()/pwrite();

3.?????????getc()/putc();

4.?????????fgetc()/fputc();

5.?????????getchar()/putchar();

6.?????????ferror()/feof();

7.?????????fgets()/fputs();

8.?????????gets()/puts();

9.?????????fread()/fwrite();

10.?????scanf()/fscanf()/sscanf()/vscanf()/vfscanf()/vsscanf()

11.?????printf()/fprintf()/sprintf()/snprintf()/vprintf()/vfprintf()/vsprintf()/vsanprintf()

12.?????readv()/writev()

13.?????read()/written()

14.?????msgrcv()/msgsnd()

15.?????revc()/recvfrom()/recvmsg()

16.?????send()/sendto()/sendmsg()

17.?????recv_fd()/send_fd()/send_err()

??粗略總結了下,有如上邊所示的17個大類,咋一看,的確讓人頭有點小暈。但是大師們都說存在的就是合理的,下邊讓我們看看,是怎么樣的深入淺出,讓這些函數有了存在的理由。要理解這些,先要知道系統在輸入輸出時所要經過的邏輯處理模塊是怎樣。如下圖示

?

以上的用戶空間的應用程序利用系統調用完成文件的讀寫過程,說明如下:

(1)???????用戶空間與內核空間;這一組關系不用說明了。

(2)???????讀與寫:都將cpu或是內存或是用戶程序看成主體,則讀,內存<-文件;寫,內存->文件;因為主體是用戶程序,所以在讀或是寫是,對讀,要確定從什么讀,對寫,向什么寫。

(3)???????應用程序利用系統服務有三條路:通過shell命令等直接實現;利用庫函數實現;直接調用系統調用的函數,如read,write等命令。在這里可以將庫函數與系統調用的關系看清楚了。系統調用是最基本的了,任何想要獲得系統服務的都要經過它,這是個關卡。

(4)???????文件I/O與標準I/O:前者是指在用戶空間中不需要其實進程明確提供一個緩沖(如圖中的bf2),其實就是進程在用戶空間直接調用read/write等函數,但是,在內核空間中都是要有緩沖的。這一般稱為文件I/O。標準I/O:提供了一種對不用緩沖I/O的函數(這些函數即可以用于不用緩沖的I/O函數,也可以有于帶有緩沖的I/O函數)的帶緩沖的接口。這一般是庫函數在用戶空間建立的(這些緩沖由庫函數完成,不需用戶自己管理,是封裝在庫函數中的),如BUF2,可能是庫函數想將對從上層接收過來的數據做個預處理,如格式變換等。使用標準I/O函數可以無需擔心如何選取最佳的緩沖區大小(由庫函數為你完成),還有一個是簡化了對輸入行的處理。標準I/O函數庫提供了使我們能夠控制該庫使用的緩沖風格的函數。

(5)???????BUF1/BUF2/BUF3:BUF1,其實是用戶空間的一些字符串,變量等,理解為數據即可。有時也定義為名稱BUF的形式,如char buf[MAXLINE];,但此時BUF只是名稱叫BUF而矣,區別于真正的緩沖區的概念。BUF2,這是庫函數為您老在用戶空間建立的,不用您親自管理,您只要一聲令下,如調用個庫函數中某個函數,自有人為你服務,這個BUF2,我們稱之為真正的緩沖區。BUF3,不論您是選擇文件I/O的形式還是標準I/O的形式,不論是哪一種,在內核中的都要用到緩沖區BUF3(這是怎么樣都免不了的),但是這個也不要用戶來親力親為,由內核代為管理。

(6)???????流(stream):這是標準為I/O中用到的,流是文件的邏輯代表,將文件I/O的:    進程->fd->文件,改變為:進程->fp(FILE對象)->流/緩沖->文件。原來對文件的操作,現在用戶只用處理:進程->流之間的操作,而流->文件之間的操作將由庫函數為你完成。流的邏輯表示就是FILE對象,而流的實體就是流使用的緩沖區,這些緩沖區相對于應用進程來說就是文件的代表。流=FILE + 緩沖。標準I/O庫提供緩沖的的是盡可能減少使用read?和write的次數。

好,暫此做以上四點說明吧,待有想法時再添加。下邊進入正題,看看上邊的這些函數,是什么形式的,為什么要有這些函數的存在,都為系統做些什么,怎么做的。

1.???????文件I/O相關(進程->fd->文件)(文件fd, buf):

(1)???????read()

形式:#include<unistd.h>

??????ssize_t??read (int filedes,??void *buf,??size_t??nbytes );

??????成功:返回讀到的字節數;出錯:返回-1;文件尾:返回0;

原因:基本系統調用功能;

實現:文件(由filedes所指)-讀nbytes字節->內存buf中。

補充:有多種情況可使實際讀到的字節數少于要求讀的字節數:

當從普通文件讀時,在讀到要求字節數之前已到達了文件尾端。

當從終端設備讀時,通常一次最多讀一行。

當從網絡讀時,網絡中緩沖機構可能造成返回值小于所要求讀的字節數。

當從管道或FIFO讀時,如若管道包含的字節少于所需的數量,那么只返回實際用

的字節數。

當從某些面向記錄的設備讀時,一次最多返回一個記錄。

當某一信號造成中斷,而已經讀了部分數據量時。

讀操作從文件的當前偏移量處開始,在成功返回之前,該偏移量將增加實際讀到的字節數。常用的unix系統shell都提供一種方法,它在標準輸入上打開一個文件,在標準輸出上追尋或重寫一個文件,這使得程序不必自行打開輸入和輸出文件。

(2)???????write()

形式:#include<unistd.h>

??????ssize_t??write (int filedes,??const void *buf,??size_t??nbytes );

??????成功:返回已寫的字節數;出錯:返回-1;

原因:基本系統調用功能;

實現:文件(由filedes所指)<-寫nbytes字節-內存buf中。

補充:write出錯的一個常見的原因是:磁盤已寫滿,或者超過了一個給定進程的文件長度限制。對于普通文件,寫操作從文件的當前偏移量處開始。如果在打開該文件時,指定了O_APPEND選項,則在每次寫操作之前,將文件偏移量設置在文件的當前結尾處。在一次成功寫之后,該文件偏移量增加實際寫的字節數。

(3)???????pread()

形式:#include<unistd.h>

??????ssize_t??pread (int filedes,???void *buf,??size_t??nbytes,??off_t??offset );

??成功:返回讀到的字節數;出錯:返回-1;到文件結尾:返回0

原因:由于lseek和read?調用之間,內核可能會臨時掛起進程,所以對同步問題造成了問題,調用pread相當于順序調用了lseek?和 read,這兩個操作相當于一個捆綁的原子操作。

實現:文件(由filedes所指)-讀nbytes字節->內存buf中。

補充:調用pread時,無法中斷其定位和讀操作,另外不更新文件指針。

(4)???????pwrite()

形式:#include<unistd.h>

??????ssize_t??pwrite (int filedes,???const void *buf,??size_t??nbytes,??off_t??offset );

??成功:返回已寫的字節數;出錯:返回-1;

原因:由于lseek和write?調用之間,內核可能會臨時掛起進程,所以對同步問題造成了問題,調用pwrite相當于順序調用了lseek?和 write,這兩個操作相當于一個捆綁的原子操作。

實現:文件(由filedes所指)<-寫nbytes字節-內存buf中。

補充:調用pwrite時,無法中斷其定位和讀操作,另外不更新文件指針。

?

2.???????流(stream)或標準I/O( 進程->fp->流(FILE+緩沖)->文件)(內存buf,?流fp):

每次輸入一個字符:

(1)???????getc();

格式:#include <stdio.h>

??????int getc(FILE *fp);

??????成功:返回下一個字符;出錯:返回EOF;文件尾:EOF;

實現:內存 <-讀一個字符c- 流(由fp所指的流,是文件的邏輯代表)

原因:在標準I/O中用,將流看成文件的邏輯代表,將對進程->文件的操作,現轉換為進程->流(也就是相當于文件)的操作。

補充:函數在返回下一個字符時,會將其unsigned char類型轉換為int類型。為不帶符號的理由是,如果最高位是1也不會使返回值為負。要求整形返回值的理由是,這樣就可以返回所有可能的字符值再加上一個已出錯或已到達文件尾端的指示值。即字符值變為正的int值,負的值就是出錯或是到達文件尾端。(負值表特殊意義),同時不論是出錯還是到達文件尾端,這三個函數都返回同樣的值即都是-1。由于每個流在FILE對象中維持了兩個標志,即出錯標志和文件結束標志,為了區分其不同,必須調用ferror或feof。

(2)???????fgetc();

格式:#include <stdio.h>

??????int fgetc(FILE *fp);

??????成功:返回下一個字符;出錯:返回EOF;文件尾:EOF;

?

實現:同getc

原因:同getc

補充:同getc

(3)???????getchar();

格式:#include <stdio.h>

??????int getchar(void);

成功:返回下一個字符;出錯:返回EOF;文件尾:EOF;

實現:內存 <-讀一個字符c- 流(由stdin所指的流,是標準輸入文件的邏輯代表),所以getchar=getc(stdin);

原因:同getc

補充:同getc

?

每次輸入一行:

(4)???????fgets();

格式:#include <stdio.h>

??????char *fgets(char *restrict buf,??Int n,??FILE *restrict??fp);

??????成功:返回buf;出錯:返回NULL;?文件結尾:NULL;

實現:內存buf <-從fp所指的流中取一行字符- 流(由fp所指)

原因:在標準I/O中用,將流看成文件的邏輯代表,將對進程->文件的操作,現轉換為進程->流(也就是相當于文件)的操作。

補充:必須指定用戶進程緩沖區的長度n,即buf的大小,此函數從流中一直讀到下一個換行符為止,但是不超過n-1個字符,讀入的字符被送入用戶緩沖區buf中。該緩沖區以null字符結尾。如若該行包括最后換行符的字數大于n-1,則其只返回一個不完整的行,但是緩沖區buf總是以null字符結尾,對此函數的調用會繼續讀該行。緩沖區buf中的內容為:(字符+換行符)+null。所以字符+換行符<=n-1,因為一定要留一個NULL字符來標識緩沖區的結束;

(5)???????gets();

格式:#include <stdio.h>

??????char *gets(char * buf);

??????成功:返回buf;出錯:返回NULL;?文件結尾:NULL;

實現:內存buf <-從stdin所指的流中取1行字符-標準輸入流(由fp=stdin所指)

原因:同上;

補充:不推薦使用,問題是調用者在使用gets時,不能指定緩沖區buf(用戶進程)的長度,這樣可能造成緩沖區溢出。

?

每次輸出一個字符:

(6)???????putc();

格式:#include <stdio.h>

??????int putc(int c ,FILE *fp);

??????成功:返回c;出錯:返回EOF;

實現:內存中整形變量c-寫字符C->流(由fp所指)。至于流什么時候將C寫入文件中,這個由庫函數來實現,不用用戶操心;

原因:

補充:

?

(7)???????fputc();

格式:#include <stdio.h>

??????int fputc(int c ,FILE *fp);

??????成功:返回c;出錯:返回EOF;

實現:內存中整形變量c-寫字符C->流(由fp所指)。至于流什么時候將C寫入文件中,這個由庫函數來實現,不用用戶操心;

原因:

補充:

?

(8)???????putchar();

格式:#include <stdio.h>

??????int putchar(int c);

??????成功:返回c;出錯:返回EOF;

實現:內存中整形變量c-寫字符C->流(由fp=stdout所指)。至于流什么時候將C寫入標準輸出文件中,這個由庫函數來實現,不用用戶操心;

原因:

補充:putchar(c)=putc(c,stdout);

?

每次輸出一行:

(9)???????fputs();

格式:#include <stdio.h>

??????int fputs(const char *restrict??str, FILE??*restrict??fp);

   成功:返回非負值;出錯:返回EOF;

實現:內存中字符數組str-寫字符數組str->流(由fp所指)。

原因:

補充:將一個以null符終止的字符串(相當于用戶空間buf,肯定有null,對應于fgets的buf中一定要有個null來標識緩沖區buf的結束。)寫到指定的流,尾端的終止符null不寫進流中。注意,這并不一定是每次輸出一行,因為它并不要求在null之前一定是換行符,buf中有就有,沒有就沒有,通常,在空字符之前是一個換行符,但并不要求總是如此。用戶空間buf:字符(+換行符)+null;流中的buf:字符+換行符。

?

(10)???puts();

格式:#include <stdio.h>

??????int puts(const char * str);

   成功:返回非負值;出錯:返回EOF;

實現:內存中字符數組str-寫字符數組str->標準輸出流(由fp=stdout所指)。

原因:

補充:將一個以null結尾的字符串寫到標準輸出上,相當于進程->流->標準輸出文件。終止符不寫出,但是puts然后又將一個換行符寫到標準輸出。應當少用,以免需要記住它在最后是否添加了一個換行符。而fgets和fputs在處理換行符,本著實事求是的態度,有就有,沒有就沒有,不會在用戶buf和流緩沖以及文件中自己添加,只是在數據經過流緩沖時,增加或是過濾到null字符。當fgets時會在用戶buf中增加一個null以標識用戶buf的結束,而fputs時,以null為終止字符,但是尾端的null并不寫在流中。

?

二進制I/O:

(11)???fread()

格式:#include <stdio.h>

??????ssize_t??fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict??fp);

??????成功:讀到的對象數。

實現:內存始址ptr<-讀N個對象- 流(由fp所指)

原因:以上有一次一個字符或是一次一行的方式進行I/O操作,當我們讀或寫一個結構時,對于一次一個字符的方式,必須循環通過整個結構,每次循環處理一個字節,一次讀或寫一個字節,這會很煩。而對于一次一行的方式,當每次結構體中有null字符時,fputs就會停止,所以也不能用它實現讀結構,同時fgets中包含有null字節或換行符,其也不能正常工作。所以要并實現結構體作為一個整體的讀或寫。

補充:使用二進制的基本問題是:它只能用于讀在同一系統上已寫的數據。其原

因是:在結構中,同一成員偏移量可能因為編譯器和系統而異,另外,用來存儲多字節整數和浮點值的二進制格式在不同的機器體系結構之間也可能不同。

?

?

(12)???fwrite()

格式:#include <stdio.h>

??????ssize_t??fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict??fp);

??????成功:寫的對象數。

?

實現:內存始址ptr-寫N個對象-> 流(由fp所指)

原因:

補充:

?

格式化輸入:文件-流->格式轉換->內存變量中

(13)???scanf();

格式:#include <stdio.h>

??????int scanf(const char *restrict format,…)

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:標準輸入流->格式轉換->內存變量中。用于分析輸入字符串,并將字符序列轉換成指定類型的變量。格式之后的各個參數包含了變量的地址,以用轉換結果初始化這些變量。

原因:要在流中做格式轉換,再將結果放到內存變量中

補充:

?

(14)???fscanf();

格式:#include <stdio.h>

??????int fscanf(FILE *restrict fp, const char *restrict format,…)

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:輸入流->格式轉換->內存變量中

原因:

補充:

?

(15)???sscanf();

格式:#include <stdio.h>

??????int sscanf(const char *restrict buf, const char *restrict format,…)

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:內存buf->格式轉換->內存變量中。

原因:

補充:對于scanf(),?從標準輸入流中輸入;fscanf,從流中輸入;?sscanf,這個比較特殊,不是從流中輸入,而是內存的一個buf相當于string中輸入。

?

(16)???vscanf();

格式:#include <stdio.h>

??????int vscanf(const char *restrict format, va_list??arg);

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:標準輸入流->格式轉換->內存變量中。用于分析輸入字符串,并將字符序列轉換成指定類型的變量。格式之后的各個參數包含了變量的地址,以用轉換結果初始化這些變量。同于scanf,只是將原來的可變參數…換成了arg;

原因:要在流中做格式轉換,再將結果放到內存變量中

補充:

?

(17)???vfscanf();

格式:#include <stdio.h>

??????int vfscanf(FILE *restrict fp, const char *restrict format, va_list??arg)

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:輸入流->格式轉換->內存變量中,?同于fscanf,只是將原來的可變參數…,換成了arg;

原因:

補充:

?

(18)???vsscanf();

格式:#include <stdio.h>

??????int vsscanf(const char *restrict buf, const char *restrict format, va_list??arg)

   成功:指定的輸入項數;出錯:返回EOF;輸入出錯或在任意變換前已到達文件結尾:EOF;

實現:內存buf->格式轉換->內存變量中。同于sscanf,只是將原來的可變參數…,換成了arg;

原因:

補充:對于scanf(),?從標準輸入流中輸入;fscanf,從流中輸入;?sscanf,這個比較特殊,不是從流中輸入,而是內存的一個buf相當于string中輸入。

?

?

格式化輸出:文件-流<-格式字符串<-內存變量

(19)???printf();

格式:#include <stdio.h>

??????int??printf(const char *restrict format, …);

??????成功:返回輸出字符數;出錯:返回負值;

實現:標準輸出流<-格式字符串<-內存變量

原因:要將內存變量的數據做格式變換,再將變換的結果放入流中

補充:

?

(20)???fprintf();

格式:#include <stdio.h>

??????int??fprintf(FILE *restrict fp,const char *restrict format, …);

??????成功:返回輸出字符數;出錯:返回負值;

實現:文件-輸出流<-格式字符串<-內存變量

原因:

補充:

?

(21)???sprint();

格式:#include <stdio.h>

??????int??sprintf(char *restrict buf, const char *restrict format, …);

??????成功:返回輸出字符數;出錯:返回負值;

實現:內存字符串buf<-格式字符串<-內存變量,就是將格式化的字符串送入數組buf而不是指定的流中。在數組的尾端自動加一個null字節,但該字節不包括在返回值中。

原因:

補充:

?

(22)???snprintf();

格式:#include <stdio.h>

??????int??snprintf(char *restrict buf, size_t n , const char *restrict format, …);

??????成功:返回輸出字符數;出錯:返回負值;

實現:內存字符串buf<-格式字符串<-內存變量,就是將格式化的字符串送入數組buf而不是指定的流中。在數組的尾端自動加一個null字節,但該字節不包括在返回值中。只能輸入n-1個字符,超過的任何字條都會被丟棄。

原因:

補充:

?

(23)???vprintf();

格式:#include <stdarg.h>

??????#include <stdio.h>

??????int??vprintf(const char *restrict format, va_list??arg);

??????成功:返回輸出字符數;出錯:返回負值;

實現:標準輸出流<-格式字符串<-內存變量,同于printf,只是將原來的可變參數…換成了arg;

原因:要將內存變量的數據做格式變換,再將變換的結果放入流中

補充:

?

(24)???vfprintf();

格式:#include <stdarg.h>

??????#include <stdio.h>

??????int??vfprintf(FILE *restrict fp,const char *restrict format, va_list??arg);

??????成功:返回輸出字符數;出錯:返回負值;

實現:輸出流<-格式字符串<-內存變量,同于fprintf,只是將原來的可變參數…換成了arg;

原因:要將內存變量的數據做格式變換,再將變換的結果放入流中

補充:

(25)???vsprintf();

格式:#include <stdarg.h>

??????#include <stdio.h>

??????int??vsprintf(char *restrict buf, const char *restrict format, va_list??arg);

??????成功:返回輸出字符數;出錯:返回負值;

實現:內存數組buf<-格式字符串<-內存變量,同于sprintf,只是將原來的可變參數…換成了arg;?就是將格式化的字符串送入數組buf而不是指定的流中。在數組的尾端自動加一個null字節,但該字節不包括在返回值中。

原因:要將內存變量的數據做格式變換,再將變換的結果放入流中

補充:

?

(26)???vsnprintf();

格式:#include <stdio.h>

??????int??vsnprintf(char *restrict buf, size_t n , const char *restrict format, va_list arg);

??????成功:返回輸出字符數;出錯:返回負值;

實現:內存字符串buf<-格式字符串<-內存變量,?同于snprintf,只是將原來的可變參數…換成了arg;?就是將格式化的字符串送入數組buf而不是指定的流中。在數組的尾端自動加一個null字節,但該字節不包括在返回值中。只能輸入n-1個字符,超過的任何字條都會被丟棄。

原因:

補充:

?

3.???????高級I/O:(文件(fd),?內存buf )

(1)???????readv()

格式:#include <sys/uio.h>

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

??????成功:返回已讀的字節數;出錯:返回-1;

實現:文件(fd)->內存向量中

原因:在一次函數調用中讀、寫多個非連續緩沖區,但是這些緩沖區已經用iovec表示好了。減少了系統調用的次數。

補充:

(2)???????writev()

格式:#include <sys/uio.h>

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

??????成功:返回已讀的字節數;出錯:返回-1;

實現:文件(fd)<-內存向量

原因:在一次函數調用中讀、寫多個非連續緩沖區,但是這些緩沖區已經用iovec表示好了。減少了系統調用的次數。

補充:

?

(3)???????readn()

格式:#include <sys/uio.h>

??????ssize_t??readn(int filedes, void *bug, size_t??nbytes);

??????成功:返回已讀的字節數;出錯:返回-1;

實現:文件(fd)->內存buf中

原因:管道、FIFO以及某些設備,特別是終端、網絡和STREAMS設備有下列兩種性質:一是,一次read操作所返回的數據可能少于所要求的數據,即使還沒達到文件尾端也可能是這樣的。這不是一個錯誤,應當繼續讀該設備。二是,一次write操作所返回的值也可能少于所指定輸出的字節數,這可能是由若干因素造成的。這些也不是錯誤,也應當繼續寫余下的數據至該設備。通常只對非阻塞描述符,或捕捉到一個信號時,才發生這種write的中途返回。但是在讀寫磁盤時,很少遇到這樣的情況。所以這個函數其實是按需要多次調用read?和write直至讀、寫了N個字節數據,即我們稱之為:直到集齊了再返回。

補充:

?

(4)???????written()

格式:#include <sys/uio.h>

??????ssize_t??writen(int filedes, void *bug, size_t??nbytes);

??????成功:返回已讀的字節數;出錯:返回-1;

實現:文件(fd)<-內存buf中

原因:管道、FIFO以及某些設備,特別是終端、網絡和STREAMS設備有下列兩種性質:一是,一次read操作所返回的數據可能少于所要求的數據,即使還沒達到文件尾端也可能是這樣的。這不是一個錯誤,應當繼續讀該設備。二是,一次write操作所返回的值也可能少于所指定輸出的字節數,這可能是由若干因素造成的。這些也不是錯誤,也應當繼續寫余下的數據至該設備。通常只對非阻塞描述符,或捕捉到一個信號時,才發生這種write的中途返回。但是在讀寫磁盤時,很少遇到這樣的情況。所以這個函數其實是按需要多次調用read?和write直至讀、寫了N個字節數據,即我們稱之為:直到集齊了再返回。

補充:

4.???????IPC中:

消息隊列中:

(1)???????msgrcv()

格式:#include <sys/msg.h>

??????ssize_t??msgrcv(int??msqid, void *ptr, size_t nbytes, long type, int flag);

??????成功:返回消息的數據部分長度;出錯:-1;

實現:消息隊列->內存消息結構體(由ptr指向)

原因:

補充:nbytes說明數據緩沖區的長度。用來構造mymesg。若返回的消息大于nbytes,而且在flag中設置了MSG_NOERROR,則該消息被截短。如果沒有設置這一標志,而消息又太長,則出錯返回E2BIG(消息仍留在隊列中。參數type我們可以指定想要哪一種消息。可以指定flag值為IPC_NOWAIT,使操作不阻塞。這使得如果沒有所指定類型的消息,則msgrcv返回-1,errno設置為ENOMSG。

?

(2)???????msgsnd()

格式:#include <sys/msg.h>

??????int??msgsnd(int??msqid, const void *ptr, size_t nbytes, long type, int flag);

??????成功:返回0;出錯:-1;

實現:消息隊列<-內存消息結構體(由ptr指向)

原因:

補充:每個消息都由三部分組成,它們是:正長整型類型字段、實際數據字節(這兩個對就myseq結構體)、非負長度(nbytes)。消息總是放在隊列尾端。ptr參數指向一個長整型數,它包含了正的整型消息類型,在其后緊跟著消息數據。可以定義如下結構:struct myseq{ long mtype; char mtex[512];}??于是ptr就是一個指向mymesg結構的指針。接收者可以用消息類型以非先進先出的次序取消息。

?

?

?

?

SOCKET中:

(1)???????revc()

格式:#include <sys/socket.h>

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

??????成功:以字節計數的消息長度;出錯:-1;無可用消息或對方已經按序結束:0;

實現:網絡sockfd-取消息msg->內存buf中。

原因:

補充:

(2)???????recvfrom()

格式:#include <sys/socket.h>

??????ssize_t??recvfrom( int sockfd, void *restrict??buf, size_t??len, int flags, struct sockaddr *restrict addr, socklen_t *restrict??addrlen);

??????成功:以字節計數的消息長度;出錯:-1;無可用消息或對方已經按序結束:0;

實現:網絡sockfd-取消息msg->內存buf中。

原因:

補充:如果addr非空,它將包含數據發送者的套接字端點地址,當調用recvfrom時,需要設置addrlen參數指向一個包含addr所指的套接字緩沖區字節大小的整數。返回時,該整數設為該地址的實際字節大小。因為可以獲得發送者的地址,recvfrom通常用于無連接套接字。

?

(3)???????recvmsg()

格式:#include <sys/socket.h>

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

??????成功:以字節計數的消息長度;出錯:-1;無可用消息或對方已經按序結束:0;

實現:網絡sockfd-取消息msg->內存buf中。

原因:

補充:結構msghdr被recvmsg用于指定接收數據的輸入緩沖區。

?

(4)???????send()

格式:#include <sys/socket.h>

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

??????成功:返回發送的字節數;出錯:-1;

實現:網絡sockfd<-取消息msg-內存buf中。

原因:

補充:如果send成功,并不必然表示連接另一端的進程接收數據。所保證的僅是當send成功返回時,數據已經無錯誤的發送到網絡上。

(5)???????sendto()

格式:#include <sys/socket.h>

??????ssize_t??sendto( int sockfd, const void *restrict??buf, size_t nbytes, int flags,??const struct sockaddr *dest addr, socklen_t * addrlen);

成功:返回發送的字節數;出錯:-1;

實現:網絡sockfd<-取消息msg-內存buf中。

原因:

補充:適用于無連接的套接字,不能使用send,除非調用connect時預先設定了目標地址,或者采用了sendto來提供另外一種報文發送方式。

?

(6)???????sendmsg()

格式:#include <sys/socket.h>

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

成功:返回發送的字節數;出錯:-1;

實現:網絡sockfd<-取消息msg-內存buf中。

原因:

補充:可以調用帶有msghdr結構的sendmsg來指定多重緩沖區傳輸數據,和writev很像。

?

傳送文件描述符(略,自行實現)

(1)???????recv_fd()

(2)???????send_fd()

(3)???????send_err()

?

總算整差不多了,雖然花了點時間,但是希望能對大家有幫助,最后謝謝閱讀!

總結

以上是生活随笔為你收集整理的Linux系统函数read()/write()/pread()/pwrite()的区别的全部內容,希望文章能夠幫你解決所遇到的問題。

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