win32下进程间通信方式之管道、邮件槽、剪切板、共享内存、消息、套接字、RPC、DDE等
生活随笔
收集整理的這篇文章主要介紹了
win32下进程间通信方式之管道、邮件槽、剪切板、共享内存、消息、套接字、RPC、DDE等
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
#include "stdafx.h"/*32位Windows采用虛擬內存技術使每個進程虛擬4G內存,在邏輯上實現了對進程之間數據代碼的分離與保護。那么相應的進程之間的通信也就有必要整理掌握一下。
Windows進程間通訊的方法有很多:管道、郵件槽、剪切板、共享內存、消息、套接字、RPC、DDE等。
但是他們大部分擁有一個共同的本質:利用Windows操作系統高2GB內核共享空間進行數據傳遞的橋梁,所以他們都是內核對象!
所以他們大部分都要遵循:A創建對象-->A寫入數據-->B打開A創建的對象-->B讀入數據的規則*///下面著重通過一些代碼Demo來加深下對進程間通信的理解//命名管道//進程A代碼#define READ_PIPE L"\\\\.\\pipe\\ReadPipe"
#define WRITE_PIPE L"\\\\.\\pipe\\WritePipe" // 管道命名typedef struct _USER_CONTEXT_
{HANDLE hPipe;HANDLE hEvent;
}USER_CONTEXT,*PUSER_CONTEXT;USER_CONTEXT Context[2] = {0};HANDLE hThread[2] = {0};BOOL WritePipe();
BOOL ReadPipe();BOOL bOk = FALSE;DWORD WINAPI WritePipeThread(LPVOID LPParam);
DWORD WINAPI ReadPipeThread(LPVOID LPParam);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hPipe = NULL;if (WritePipe()==FALSE){return -1;}if (ReadPipe()==FALSE){return -1;}int iIndex = 0;while (TRUE){ if (bOk==TRUE){SetEvent(Context[0].hEvent);SetEvent(Context[1].hEvent);Sleep(1);}iIndex = WaitForMultipleObjects(2,hThread,TRUE,5000);if (iIndex==WAIT_TIMEOUT){continue;}else{break;}}int i = 0;for (i=0;i<2;i++){CloseHandle(Context[i].hEvent);CloseHandle(Context[i].hPipe);}CloseHandle(hThread[0]);CloseHandle(hThread[1]);cout<<"Exit"<<endl;return nRetCode;
}BOOL WritePipe()
{HANDLE hWritePipe = NULL;hWritePipe = CreateNamedPipe( WRITE_PIPE, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, MAX_PATH, MAX_PATH,0, NULL); if (hWritePipe==INVALID_HANDLE_VALUE){return FALSE;}HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);Context[0].hEvent = hEvent;Context[0].hPipe = hWritePipe;hThread[0] = CreateThread(NULL,0,WritePipeThread,NULL,0,NULL);return TRUE;
}BOOL ReadPipe()
{HANDLE hReadPipe = NULL;hReadPipe = CreateNamedPipe( READ_PIPE, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, MAX_PATH, MAX_PATH,0, NULL); if (hReadPipe==INVALID_HANDLE_VALUE){return FALSE;}HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);Context[1].hEvent = hEvent;Context[1].hPipe = hReadPipe;hThread[1] = CreateThread(NULL,0,ReadPipeThread,NULL,0,NULL);return TRUE;}DWORD WINAPI ReadPipeThread(LPVOID LPParam)
{HANDLE hEvent = Context[1].hEvent;HANDLE hReadPipe = Context[1].hPipe;DWORD dwReturn = 0;char szBuffer[MAX_PATH] = {0};int iIndex = 0;while (TRUE){iIndex = WaitForSingleObject(hEvent,30);iIndex = iIndex-WAIT_OBJECT_0;if (iIndex==WAIT_FAILED||iIndex==0){break;}if (ReadFile(hReadPipe,szBuffer,MAX_PATH,&dwReturn,NULL)){szBuffer[dwReturn] = '\0';cout<<szBuffer<<endl;}else{if (GetLastError()==ERROR_INVALID_HANDLE){break;} }}return 0;
}DWORD WINAPI WritePipeThread(LPVOID LPParam)
{HANDLE hEvent = Context[0].hEvent;HANDLE hWritePipe = Context[0].hPipe;DWORD dwReturn = 0;char szBuffer[MAX_PATH] = {0};int iIndex = 0;while (TRUE){iIndex = WaitForSingleObject(hEvent,30);iIndex = iIndex-WAIT_OBJECT_0;if (iIndex==WAIT_FAILED||iIndex==0){break;}cin>>szBuffer; if (WriteFile(hWritePipe,szBuffer,strlen(szBuffer),&dwReturn,NULL)){}else{if (GetLastError()==ERROR_INVALID_HANDLE){break;} }}return 0;
}//進程B代碼#define WRITE_PIPE L"\\\\.\\pipe\\ReadPipe"
#define READ_PIPE L"\\\\.\\pipe\\WritePipe"HANDLE hThread[2] = {0};DWORD WINAPI ReadPipeThread(LPARAM LPParam);
DWORD WINAPI WritePipeThread(LPARAM LPParam);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{HANDLE hReadPipe = NULL;HANDLE hWritePipe = NULL;hThread[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadPipeThread,NULL,0,NULL);hThread[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WritePipeThread,NULL,0,NULL);WaitForMultipleObjects(2,hThread,TRUE,INFINITE);CloseHandle(hReadPipe);CloseHandle(hWritePipe);CloseHandle(hThread[0]);CloseHandle(hThread[1]);cout<<"Exit"<<endl;return -1;
}DWORD WINAPI WritePipeThread(LPARAM LPParam)
{HANDLE hWritePipe = NULL;char szBuffer[MAX_PATH] = {0};DWORD dwReturn = 0;while(TRUE){hWritePipe = CreateFile(WRITE_PIPE,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);if (hWritePipe==INVALID_HANDLE_VALUE){continue;}break;}while (TRUE){cin>>szBuffer;if (WriteFile(hWritePipe,szBuffer,MAX_PATH,&dwReturn,NULL)){}else{if (GetLastError()==ERROR_NO_DATA){cout<<"Write Failed"<<endl;break;}}}return 0;
}DWORD WINAPI ReadPipeThread(LPARAM LPParam)
{HANDLE hReadPipe = NULL;char szBuffer[MAX_PATH] = {0};DWORD dwReturn = 0;while(TRUE){hReadPipe = CreateFile(READ_PIPE,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);if (hReadPipe==INVALID_HANDLE_VALUE){continue;}break;}while (TRUE){if (ReadFile(hReadPipe,szBuffer,MAX_PATH,&dwReturn,NULL)){szBuffer[dwReturn] = '\0';cout<<szBuffer;}else{cout<<"Read Failed"<<endl;break;}}return 0;
}/*其中進程A創建了管道內核對象,以及用于讀寫管道的雙線程。B進程通過對象名打開了A創建的內核對象,同時也創建了雙線程進行命名管道的讀與寫。
對于管道需要多說的是有一種管道是匿名管道,也就是不需要創建對象管道的名字。那么其他進程又是如何知道這個管道對象,從而實現對信息的傳遞的呢?
原來它是通過內核對象的可繼承性進行的,也就是說匿名管道只能作用于父子進程之間,在父進程創建子進程的時候通過對CreateProcess函數中傳參,即可讓子進程獲得父進程的內核對象句柄。
具體實現細節,請參考《Windows核心編程》內核對象一章。*///郵件槽//進程A代碼#define MAIL_SLOT_NAME L"\\\\.\\mailslot\\Name" HANDLE hReadMailSlot = INVALID_HANDLE_VALUE;
DWORD WINAPI ReadMail();
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hReadThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadMail,NULL,0,NULL);Sleep(INFINITE);if (hReadMailSlot!=INVALID_HANDLE_VALUE){CloseHandle(hReadMailSlot);}Sleep(10);return nRetCode;
}DWORD WINAPI ReadMail()
{hReadMailSlot = CreateMailslot(MAIL_SLOT_NAME,0,0,NULL);if (hReadMailSlot==INVALID_HANDLE_VALUE){return -1;}//查看油槽的信息DWORD cbMessage = 0;DWORD cMessage = 0;BOOL bOk = FALSE;char* szBuffer = NULL;DWORD dwReturn = 0;while (TRUE){bOk = GetMailslotInfo(hReadMailSlot,NULL,&cbMessage,&cMessage,NULL);if (bOk==FALSE){break;}if (cMessage==0){continue;}else{if (szBuffer!=NULL){free(szBuffer);szBuffer = NULL;}szBuffer = (char*)malloc(sizeof(char)*cbMessage+1);if (ReadFile(hReadMailSlot, szBuffer, cbMessage, &dwReturn, NULL)==TRUE){szBuffer[dwReturn] = '\0';if (strcmp(szBuffer,"Exit")==0){break;}cout<<szBuffer<<endl;} }}cout<<"ReadThread Exit"<<endl;
}//進程B代碼#define MAIL_SLOT_NAME L"\\\\.\\mailslot\\Name"
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hWriteMailSlot = NULL;while(TRUE){hWriteMailSlot = CreateFile(MAIL_SLOT_NAME,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hWriteMailSlot==INVALID_HANDLE_VALUE){continue;}else{break;}}DWORD dwReturn = 0;char szBuffer[1024] = {0};while (TRUE){cin>>szBuffer;if (strcmp(szBuffer,"Exit")==0){break;}WriteFile(hWriteMailSlot,szBuffer,strlen(szBuffer),&dwReturn,NULL);}WriteFile(hWriteMailSlot,szBuffer,strlen(szBuffer),&dwReturn,NULL);CloseHandle(hWriteMailSlot);return nRetCode;
}/*郵件槽的實現和命名管道大同小異,都是A創建對象-->A寫入數據-->B打開A創建的對象-->B讀入數據。以前一直認為郵件槽是Windows與Linux共有的機制,自從某次上Liunx課和老師討論了一會進程間通信的問題,
才愚蠢的知道Linux并沒有郵件槽這個機制。*///共享內存//進程A代碼using namespace std;int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;char szBuffer[] = "Shine";HANDLE hMapping = CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,4096,L"ShareMemory");LPVOID lpBase = MapViewOfFile(hMapping,FILE_MAP_WRITE|FILE_MAP_READ,0,0,0);strcpy((char*)lpBase,szBuffer);Sleep(20000);UnmapViewOfFile(lpBase);CloseHandle(hMapping);return nRetCode;
}//進程B代碼int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,L"ShareMemory");if (hMapping){wprintf(L"%s\r\n",L"Success");LPVOID lpBase = MapViewOfFile(hMapping,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);char szBuffer[20] = {0};strcpy(szBuffer,(char*)lpBase);printf("%s",szBuffer);UnmapViewOfFile(lpBase);CloseHandle(hMapping);}else{wprintf(L"%s",L"OpenMapping Error");}return nRetCode;
}/*說道共享內存不得不說下內存映射:如何將一個文件映射到自己的緩沖區中。
打開文件-->計算文件大小-->創建內存映射對象Mapping-->mapofviewfile映射到自己的緩沖區中
通過文件映射來進行讀寫文件操作較為方便。*///文件映射代碼int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{int nRetCode = 0;HANDLE hFile = CreateFile(L"D:\\Demo.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);DWORD dwHigh = 0;DWORD dwLow = 0;dwLow = GetFileSize(hFile,&dwHigh); dwLow = ((dwLow + 4095)/4096)*4096;if (hFile==INVALID_HANDLE_VALUE){return -1;}HANDLE hMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,dwHigh,dwLow,NULL);if (hMapping==NULL){CloseHandle(hFile);}char* szBuffer = NULL;szBuffer = (char*)MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (szBuffer!=NULL){cout<<szBuffer<<endl;}*(szBuffer+1) = 'w';UnmapViewOfFile(szBuffer);CloseHandle(hMapping);CloseHandle(hFile);return nRetCode;
}//消息//進程A代碼void CServerDlg::OnBnClickedOk()
{CString strBuffer;m_Edit.GetWindowText(strBuffer);if (strBuffer.GetLength()==0){return;}COPYDATASTRUCT Temp;Temp.dwData = 0; Temp.cbData = strBuffer.GetLength()*sizeof(WCHAR); // sizeof 沒有算 '\0'Temp.lpData = strBuffer.GetBuffer(); HWND hFindWindow = ::FindWindow(NULL,L"Client");if (hFindWindow==NULL){return;}::SendMessage(hFindWindow,WM_COPYDATA,NULL,(LPARAM)&Temp);}//進程B代碼//進程B需要添加WM_COPYDATA消息BOOL CClientDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{// TODO: 在此添加消息處理程序代碼和/或調用默認值if (pCopyDataStruct->lpData==NULL||pCopyDataStruct->cbData==0){return FALSE;}int nSize = 0; //字節20int nLen = pCopyDataStruct->cbData+sizeof(WCHAR); //字符HelloWorld10 加了個'\0'WCHAR* szBuffer = new WCHAR[nLen>>1]; // 右移一位 除以二 申請 同樣大的內存if (szBuffer==NULL){return FALSE;}memset(szBuffer,0,sizeof(WCHAR)*(nLen>>1));memcpy(szBuffer,pCopyDataStruct->lpData,pCopyDataStruct->cbData);m_Edit.SetWindowText(szBuffer);delete szBuffer;szBuffer = NULL;return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
總結
以上是生活随笔為你收集整理的win32下进程间通信方式之管道、邮件槽、剪切板、共享内存、消息、套接字、RPC、DDE等的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络开源框架之libevent使用实例
- 下一篇: Linux下进程间通信方式之管道、信号、