2009-04-12 6 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

+0

Да, obj1 - это больше сервер, а obj2 - как клиент, который будет запущен позже. – samoz

ответ

24

Несколько вопросов:

  1. Избегайте смешивания высокого уровня ввода-вывода (Еореп(), FSEEK()) и некоторые низкоуровневые операции, как ттар /(). Хотя вы можете получить низкоуровневый файловый дескриптор, используя fileno(), это походит на то, чтобы взять самый длинный маршрут, чтобы добраться до того же места. Кроме того, просто использование mmap() нарушает совместимость за пределами BSD и POSIX, поэтому вы ничего не получаете, используя стандартные функции ввода/вывода C. Просто используйте open() и lseek() напрямую.
  2. Не имеет смысла использовать потоковый форматированный ввод-вывод (fprintf()) в том же файле, что и картографирование памяти. Когда вы сохраняете карту памяти, вы неявно говорите системе, что собираетесь использовать ее как данные с прямым доступом (прямой индексацией). fprintf() для вывода потока, вы обычно используете его для последовательного доступа. На самом деле, хотя это возможно, необычно видеть fprintf() и fseek() в одном и том же дескрипторе (это даже не переносимо, но из-за предыдущего элемента я не рассматриваю переносимость).
  3. Защита должна соответствовать защите открытого файла. Поскольку вы передаете «w» для fopen() и PROT_READ | PROT_WRITE | PROT_EXEC в mmap(), вы нарушаете это ограничение. Это также указывает на то, почему вы не должны смешивать высокоуровневый ввод-вывод с отображением памяти: как вы гарантируете, что fopen(...,"w") откроет файл с правильными флагами? Предполагается, что это будет «реализация-деталь» для библиотеки C. Если вы хотите создать карту памяти с правами на чтение и запись, вы должны использовать низкоуровневый open(theSharedFileName, O_RDWR), чтобы открыть файл.
  4. Не используйтеPROT_WRITE и PROT_EXEC вместе. Он не переносится и - это риск для безопасности. Читайте о W^X и executable space protection.
+0

Очень полный ответ. – Anthony

+1

Некоторые из этих ответов кажутся дезинформацией. Я смущен, почему вы думаете, что 'fprintf' и' fseek' нельзя использовать совместно. А что касается # 3 и режимов файлов, POSIX очень точно указывает, как строки режима 'fopen' переходят в режимы дескриптора файла; это не зависит от реализации. –

1

Как говорили другие, не используйте для этого fopen() и друзей.

Часть проблемы, с которой вы столкнулись, может быть связана с тем, что fprintf() может иметь потоковые буферы, поэтому он может фактически не изменять файл и, следовательно, быть видимым для другого процесса, если ожидается. Вы можете добавить fflush(), но read() и write() не выполняют буферизацию на уровне приложений, что является частью того, почему они более подходят.

2

Если вы можете использовать C++ и библиотеки, такие как ACE или Boost, которые защищают вас от деталей низкого уровня и обеспечивают более легкую абстракцию для IPC.