2009-04-12 82 views
4

我試圖讓兩個不同的進程通過使用內存映射相同的文件進行通信。不過,我在這方面遇到了一些問題。我有一種感覺,這與我使用open()調用並將文件描述符傳遞給mmap的方式有關。通過文件使用mmap

這是我的代碼,你能看到它有什麼問題嗎?

對象1的代碼:

16  FILE* temp = fopen(theSharedFileName, "w"); 
17  fseek(temp, fileSize-1, SEEK_SET); 
18  fprintf(temp, "0"); // make the file a certain size 
19  fseek(temp, 0, SEEK_CUR); 
20 
21  int sharedFileName = fileno(temp); 
... 
31  sharedArea = (MyStruct*)mmap(0, fileSize, 
32   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, sharedFileName, 0); 

我使用「w」文件模式,因爲對象1將只進行一次,我希望它重置以前已有的數據。

對象2的代碼:

130  FILE* tempFile = fopen(sharedFileName, "a"); 
131  int theFile = fileno(tempFile); 
... 
135  sharedArea = (MyStruct*)mmap(NULL, fileSize, 
136   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, theFile, 0); 
+0

你面臨的確切問題是什麼?你能保證obj2在obj1之前永遠不會訪問文件嗎? – dirkgently 2009-04-12 23:12:24

+0

是的,obj1更像是一個服務器,而obj2就像稍後會啓動的客戶端。 – samoz 2009-04-13 12:55:40

回答

24

的幾個問題:

  1. 切忌混高層I/O(fopen()函數,FSEEK())和一些低級別的類似MMAP操作()。儘管可以使用fileno()獲取低級別文件描述符,這就像是使用最長的路徑到達同一個地方。另外,僅僅使用mmap()可以打破BSD和POSIX之外的兼容性,所以通過使用標準的C I/O函數你什麼也得不到。直接使用open()和lseek()。
  2. 在存儲器映射的相同文件上使用流格式化的I/O(fprintf())沒有意義。當你記憶一個文件時,你隱式地告訴系統你要用它作爲隨機訪問(直接索引)數據。 fprintf()用於流輸出,通常用於順序訪問。事實上,雖然可能,但在同一個描述符中看到fprintf()和fseek()是不尋常的(這甚至不是可移植的,但是由於之前的項目,我沒有考慮可移植性)。
  3. 保護必須匹配打開的文件保護。由於您將「w」傳遞給fopen(),並將PROT_READ | PROT_WRITE | PROT_EXEC傳遞給mmap(),因此違反了此​​限制。這也強調了爲什麼你不應該混合使用高級I/O和內存映射:你如何保證fopen(...,"w")將打開帶有正確標誌的文件?這應該是C庫的「實現 - 細節」。如果要以讀取和寫入權限對文件進行內存映射,則應使用低級別open(theSharedFileName, O_RDWR)來打開文件。
  4. 不要使用PROT_WRITEPROT_EXEC在一起。它不是便攜式的這是一個安全風險。閱讀關於W^Xexecutable space protection
1

正如其他人所說的,不要使用fopen()和這個朋友。

您遇到的部分問題可能是由於fprintf()可能具有流緩衝區的事實,因此它可能實際上不會更改該文件,因此在預期的情況下對其他進程可見。您可以添加fflush(),但read()和write()不會執行任何應用程序級緩衝,這是它們更合適的原因之一。

2

如果您可以使用C++和ACEBoost等庫來屏蔽您的低級別細節併爲IPC提供更容易的抽象。