總結下linux下的IPC使用原理及注意事項

2021-05-26 13:16:18 字數 3416 閱讀 1505

首先說明一下mmap函式用途:

採用共享記憶體通訊的乙個顯而易見的好處是效率高,因為程序可以直接讀寫記憶體,而不需

要任何資料的拷貝

1、將乙個普通檔案對映到記憶體中,通常在需要對檔案進行頻繁讀寫時使用,這樣用記憶體讀

寫取代i/o讀寫,以獲得較高的效能;

2、將特殊檔案進行匿名記憶體對映,可以為關聯程序提供共享記憶體空間;

適用於具有親緣關係的程序之間。由於父子程序特殊的親緣關係,在父程序中先呼叫mmap

(),然後呼叫 fork()。那麼在呼叫fork()

之後,子程序繼承父程序匿名對映後的位址空間,同樣也繼承mmap()

返回的位址,這樣,父子程序就可以通過對映區域進行通訊了。

3、為無關聯的程序提供共享記憶體空間,一般也是將乙個普通檔案對映到記憶體中。

普通檔案fd用於mmap引數:

1、最終被對映檔案的內容的長度不會超過檔案本身的初始大小,即對映不能改變檔案的大小

2、記憶體的保護是以頁為基本單位的,即使被對映檔案只有乙個位元組大小,核心也會為對映分

配乙個頁面大小的記憶體,用於程序間通訊的有效位址空間大小不會超過檔案大小及乙個頁

面大小的和

3、檔案一旦被對映後,呼叫mmap()的程序對返回位址的訪問是對某一記憶體區域的訪問,暫時

脫離了磁碟上檔案的影響,只有在呼叫了munmap()後或者msync()時,才把記憶體中的相應

內容寫回磁碟檔案,所寫內容仍然不能超過檔案的大小。

a、ftok使用說明

key_t ftok( char * fname, int id )  fname就時你指定的檔名,id是子序號。

在一般的unix實現中,是將檔案的索引節點號取出,前面加上子序號得到key_t的返回值。

如指定檔案的索引節點號為65538,換算成16進製為0x010002,而你指定的id值為38,換

算成16進製為0x26,則最後的key_t返回值為0x26010002。

當刪除重建檔案後,索引節點號由作業系統根據當時檔案系統的使用情況分配,因此與原來

不同,所以得到的索引節點號也不同。

如果要確保key_t值不變,要目確保ftok的檔案不被刪除,要麼不用ftok,指定乙個固定的key_t值

注意:ftok將乙個已存在的路徑名和乙個整數識別符號轉換成乙個key_t值。 

ftok會組合三個值來產生key:

1、pathname所在的檔案系統的資訊。

2、該檔案在本檔案系統內的索引節點號。

3、id的低序8位。 

key_t

的生成是以乙個已存在的檔案作為輸入,並不是簡單的字串雜湊函式,必須真正存在某

個檔案,才能將其位置傳入ftok。

b、檔案空洞是怎麼回事

off_t lseek(int filedes, off_t offset, int whence);

引數 offset 的含義取決於引數 whence:

當前檔案偏移量(current file offset),以下簡稱為 cfo,非負整數

1. 如果 whence 是 seek_set,檔案偏移量將被設定為 offset。

2. 如果 whence 是 seek_cur,檔案偏移量將被設定為 cfo 加上 offset,

offset 可以為正也可以為負。

3. 如果 whence 是 seek_end,檔案偏移量將被設定為檔案長度加上 offset,

offset 可以為正也可以為負。

注意: 對於普通檔案(regular file),cfo 是乙個非負整數。但對於特殊裝置,cfo 

有可能是負數。因此,我們不能簡單地測試 lseek 的返回值是否小於 0 來判斷 lseek 

成功與否,而應該測試 lseek 的返回值是否等於 -1 來判斷 lseek 成功與否。

if (lseek(fd, 16384, seek_set) == -1)

測試結果表明,lseek並不能extend檔案大小,需要write一下0的資料

/*** 參看前面man手冊中的說明,mmap()不能用於擴充套件檔案長度。所以這裡必須事

* 先擴大目標檔案長度,準備乙個空架子等待後面讀寫使用:

* 如果 offset 比檔案的當前長度更大,下乙個寫操作就會把檔案「撐大(extend)」。

* 這就是所謂的在檔案裡創造「空洞(hole)」。沒有被實際寫入檔案的所有位元組

* 由重複的 0 表示。空洞是否占用硬碟空間是由檔案系統(file system)決定的

*/ int tmpdata = 0x00;

lseek(fd,maxsize-4,seek_set);

write(fd,(const void*)&tmpdata,sizeof(ui32)); /* 寫入乙個int型資料長度 */

或者write(fd, "\0", 1); /* 在檔案最後新增乙個空字元 */

也可以使用ftruncate(改變檔案大小)進行設定大小。

即對於普通檔案的對映前,首稱必須將fd的檔案擴充套件到與你所對映空間的同樣大小,這

樣子後面對映後才可使用,否過會越界使用而出現宕機

high memory |-------| a

|       |

|       |

|       |

|       |

low memory  |-------| b

|offfset|   len   |

|-----------------|

a'       b'

c、copy_to_user與mmap的工作原理

copy_to_user

在每次拷貝時需要檢測指標的合法性,也就是使用者空間的指標所指向的位址的確是一段

該程序本身的位址,而不是指向了不屬於它的地方,而且每次都會拷貝一次資料,頻繁

訪問記憶體,由於虛擬位址連續,實體地址不一定會連續,從而造成cpu的cache頻繁失效,

從而使速度降低

mmap優點:

僅在第一次使用時為程序建立頁表,也就是將一段物理位址對映到一段虛擬位址上,以後

操作時不再檢測其位址的合法性(合法**由cpu頁保護異常來做),另一方面是核心下

直接操作mmap位址,可以不用頻繁拷貝,也就是說在核心下直接可用指標向該位址操作,

而不再在核心中專門開乙個緩衝區,然後將緩衝區中的資料拷貝一次進來,mmap一般是

將一段連續的物理位址對映成一段虛擬位址,當然,也可以將每段連續,但各段不連續

的物理位址對映成一段連續的虛擬位址,無論如何,其實體地址在每段之中是連續的,

這樣一來,就不會造成cpu的cache頻繁失效,從而大大節約時間

總結:mmap 位址影射 包括 

a、記憶體實體地址 -- 虛擬位址

b、檔案裝置--虛擬位址 

目的是通過 虛擬位址訪問 目標位址 ,目標位址 包括 實體地址 檔案裝置等

Linux下的IPC 命名管道的使用

程序之間通過管道來進行通訊是一種常用的方法,顧名思義,管道就是一端進 寫 一端出 讀 的fifo佇列,這個佇列由核心管理,有一定大小 一般是4k 有文章上提到,如果需要修改該快取區,需要重新編譯核心 修改linux limits.h裡pipe buf的定義 需要明確的是,雖然管道在理論上是雙向的,但...

linux檔案操作總結(下)

建立目錄 include include int mkdir const char path,mode t mode 目錄路徑 目錄許可權 若執行成功則返回0,失敗則返回 1,錯誤 存入errno刪除目錄 include include int mkdir const char path,mode ...

Linux 下的IPC控制命令

shell環境控制ipc ipc物件一經建立,系統核心即會為該物件分配相關資料結構。為了方便對ipc物件的管理,linux系統提供了專門的ipc控制命令,主要包括檢視ipc物件資訊的ipcs和刪除ipc物件的ipcrm。1 檢視ipc物件資訊 ipcs 引數 1 引數說明 a 檢視全部ipc物件資訊...