两个进程之间的命名共享内存

Posted

技术标签:

【中文标题】两个进程之间的命名共享内存【英文标题】:named shared memory between two processes 【发布时间】:2014-09-02 23:30:52 【问题描述】:

我正在尝试使用文件映射在 C 中构建客户端/服务器,它仍处于开发的早期阶段,但我在理解文件映射的确切工作原理时遇到了一些麻烦。

我在我的服务器上创建了一个结构的文件映射并将一些数据放在上面,然后我的客户端打开文件映射并读取数据。然后我的客户端写入数据供服务器读取,但服务器无法读取客户端数据,我不明白为什么,因为文件映射应该在两个进程之间同步。在这个阶段我仍然没有使用事件,但我认为它不需要它们来工作(是吗?)

她是我的密码。

服务器:

struct _HBACKUPSERVICE
    DWORD           dwServerProcessID;
    TCHAR           szWork[MAX_PATH];
    HANDLE          hMapFile;
;

PHBACKUPSERVICE pBuf = NULL;
HANDLE hMapFile;

hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,    // use paging file
    NULL,                    // default security
    PAGE_READWRITE,          // read/write access
    0,                       // maximum object size (high-order DWORD)
    sizeof(HBACKUPSERVICE),  // maximum object size (low-order DWORD)
    _T("MyService"));        // name of mapping object

if (/*phBackupService->*/hMapFile == NULL)
    _tprintf(TEXT("Could not create file mapping object (%d).\n"),
        GetLastError());
    return *pBuf;


pBuf = (PHBACKUPSERVICE)MapViewOfFile(
    hMapFile,               // handle to map object
    FILE_MAP_ALL_ACCESS,    // read/write permission
    0,
    0,
    sizeof(HBACKUPSERVICE));

if (pBuf == NULL)
    _tprintf(TEXT("Could not map view of file (%d).\n"),
        GetLastError());
    return *pBuf;



// Populate backup service structure
pBuf->hMapFile = hMapFile;
pBuf->dwServerProcessID = GetCurrentProcessId();

// Wait for client
do
    _tprintf(_T("\nServer: Waiting for work."));
    pBuf = (PHBACKUPSERVICE)MapViewOfFile(
        _BackupService.hMapFile,    // handle to map object
        FILE_MAP_ALL_ACCESS,        // read/write permission
        0,
        0,
        sizeof(HBACKUPSERVICE));
    if (StringCbLength(pBuf->szWork, 1 * sizeof(TCHAR), NULL) == S_OK) Sleep(500); 
 while (StringCbLength(pBuf->szWork, 1 * sizeof(TCHAR), NULL) == S_OK); // ERROR: pBuf->szWork is always empty...

_tprintf(_T("Work from client: %s"), pBuf->szWork);

客户:

HBACKUPSERVICE _BackupService;
HANDLE hMapFile;

hMapFile = OpenFileMapping(
    FILE_MAP_ALL_ACCESS,   // read/write access
    FALSE,                 // do not inherit the name
    _T("MyService"));          // name of mapping object

if (hMapFile == NULL)

    _tprintf(TEXT("Could not open file mapping object (%d).\n"),
        GetLastError());


BackupService= (PHBACKUPSERVICE)MapViewOfFile(
    hMapFile,               // handle to map object
    FILE_MAP_ALL_ACCESS,    // read/write permission
    0,
    0,
    sizeof(HBACKUPSERVICE));

_tprintf(_T("Server process id: %d"), _BackupService.dwServerProcessID);
_tprintf(_T("send work to server"));
StringCchCopy(_BackupService.szWork, STRSAFE_MAX_CCH, _T("Do work for me!!!!!!!!!!")); //ERROR: the server never sees this

谢谢!

【问题讨论】:

您确定您的客户端确实正确写入了吗?您是否尝试阅读您刚刚写的内容? 是的,客户端写入共享结构 可能是缓存问题导致服务器实际上没有重新读取写入的内容 我不这么认为,结构在两个进程上都映射到内存,所以理论上两者都应该“看到”同一个对象 【参考方案1】:

您的服务器在其读取循环中调用MapViewOfFile(),因此您正在映射越来越多的指针而不是取消映射它们。最终,您将用完可用的映射地址。摆脱它。在进入循环之前,您应该使用已经从第一个 MapViewOfFile() 获得的 pBuf 指针。您只需映射视图一次。

您的客户端根本没有将数据写入映射视图,而是写入本地HBACKUPSERVICE 变量而不是映射视图。这就是服务器看不到数据的原因。

试试这个:

常见:

typedef struct _HBACKUPSERVICE 
    DWORD           dwServerProcessID;
    TCHAR           szWork[MAX_PATH];
    HANDLE          hMapFile;
 HBACKUPSERVICE, *PHBACKUPSERVICE;

服务器:

PHBACKUPSERVICE pBuf = NULL;
HANDLE hMapFile;

hMapFile = CreateFileMapping(
    INVALID_HANDLE_VALUE,    // use paging file
    NULL,                    // default security
    PAGE_READWRITE,          // read/write access
    0,                       // maximum object size (high-order DWORD)
    sizeof(HBACKUPSERVICE),  // maximum object size (low-order DWORD)
    _T("MyService"));        // name of mapping object

if (hMapFile == NULL)
    _tprintf(TEXT("Could not create file mapping object (%d).\n"),
        GetLastError());
    return NULL;


pBuf = (PHBACKUPSERVICE)MapViewOfFile(
    hMapFile,               // handle to map object
    FILE_MAP_ALL_ACCESS,    // read/write permission
    0,
    0,
    sizeof(HBACKUPSERVICE));

if (pBuf == NULL)
    _tprintf(TEXT("Could not map view of file (%d).\n"),
        GetLastError());
    return NULL;


// Populate backup service structure
pBuf->hMapFile = hMapFile;
pBuf->dwServerProcessID = GetCurrentProcessId();
ZeroMemory(pBuf->szWork, sizeof(pBuf->szWork));

// Wait for client
_tprintf(_T("\nServer: Waiting for work."));
while (pBuf->szWork[0] == 0) Sleep(500); 

_tprintf(_T("Work from client: %s"), pBuf->szWork);

客户:

PHBACKUPSERVICE BackupService = NULL;
HANDLE hMapFile;

hMapFile = OpenFileMapping(
    FILE_MAP_ALL_ACCESS,   // read/write access
    FALSE,                 // do not inherit the name
    _T("MyService"));          // name of mapping object

if (hMapFile == NULL)

    _tprintf(TEXT("Could not open file mapping object (%d).\n"),
        GetLastError());


BackupService = (PHBACKUPSERVICE)MapViewOfFile(
    hMapFile,               // handle to map object
    FILE_MAP_ALL_ACCESS,    // read/write permission
    0,
    0,
    sizeof(HBACKUPSERVICE));

if (BackupService == NULL)
    _tprintf(TEXT("Could not map view of file (%d).\n"),
        GetLastError());


_tprintf(_T("Server process id: %d"), BackupService->dwServerProcessID);
_tprintf(_T("send work to server"));
StringCchCopy(BackupService->szWork, MAX_PATH, _T("Do work for me!!!!!!!!!!"));

最后,TCHAR 对于跨进程边界的互操作是危险的。想象一下,如果一个 ANSI 应用程序试图与一个 UNICODE 应用程序通信会发生什么。他们不会同意您的 szWork 字段的格式,因此不同意您的 HBACKUPSERVICE 结构的字节大小。您应该根据需要将TCHAR 替换为CHARWCHAR,并在两端保持一致。

【讨论】:

这工作:) 谢谢。我害怕使用指针,因为我不知道它们在使用的不同进程中会如何表现,但它完全有效。还要感谢有关 TCHAR 的提醒,但这只是学术性的,我们被要求使用 Unicode。 如果您被要求使用 Unicode,那么您应该使用 WCHARCreateFileMappingW()OpenFileMappingW()wprintf()StringCchCopyW()

以上是关于两个进程之间的命名共享内存的主要内容,如果未能解决你的问题,请参考以下文章

如何在工作在同一共享内存区域的两个进程之间共享锁?

共享内存

在两个进程之间共享内存(C、Windows)

进程通信之共享内存

共享内存的实现

Linux 进程间通信 --共享内存