【问题标题】:Using mmap over a file在文件上使用 mmap
【发布时间】:2009-04-12 22:49:08
【问题描述】:

我试图通过使用内存映射同一文件来允许两个不同的进程进行通信。但是,我对此有一些问题。我感觉这与我使用 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);

【问题讨论】:

  • 您面临哪些具体问题?你能保证 obj2 永远不会在 obj1 之前访问该文件吗?
  • 是的,obj1更像是一个服务器,而obj2更像是一个稍后会启动的客户端。

标签: c file mmap


【解决方案1】:

几个问题:

  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

【讨论】:

  • 这个答案的某些部分似乎是错误信息。我很困惑为什么你认为fprintffseek 不能便携地一起使用。至于#3 和文件模式,POSIX 非常明确地指定了fopen 模式字符串如何转换为文件描述符模式;它不是特定于实现的。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多