在文件上使用mmap

时间:2009-04-12 22:49:08

标签: c file mmap

我正在尝试允许两个不同的进程通过使用内存映射相同的文件进行通信。但是,我遇到了一些问题。我有一种感觉,这与我使用open()调用并将我的文件描述符传递给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);

3 个答案:

答案 0 :(得分: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 :(得分:2)

如果您可以使用C ++和ACEBoost这样的库来保护您免受低级别细节的影响,并为IPC提供更简单的抽象。

答案 2 :(得分:1)

正如其他人所说,不要使用fopen()和朋友。

您遇到的部分问题可能是由于fprintf()可能具有流缓冲区,因此它实际上可能无法更改文件,因此在预期时对其他进程可见。你可以添加一个fflush(),但read()和write()不做任何应用程序级缓冲,这是它们更合适的部分原因。