文章目录
// 进程之间共享数据,一般用在dll中;
#pragma data_seg("shared") // 名称任意,长度不能超过8个字符,section亦未加点'.'
int g_iTotal = 0; // 共享的数据必须初始化,否则不会放到共享数据段中
#pragma data_seg ()
#pragma comment(linker,"/section:shared,RWS") // RWS:读,写,共享
Pipe
底层是依照共享内存来实现的!
- 匿名管道:父子进程间通信.单向,不支持异步读写!
- 每一个管道都有Read,Write两端,只需要有一端连接到某个线程的标准输出.
- 如果还需要控制某个线程的标准输入,则需再建立一个管道把StdInRead端连接到该线程input端.
- 具体例子可参照
xProcess.h
BOOL WINAPI CreatePipe(
PHANDLE hReadPipe,
PHANDLE hWritePipe,
LPSECURITY_ATTRIBUTES lpPipeAttributes,
DWORD nSize // can be zero
);
HANDLE WINAPI CreateNamedPipe( // 不同机器的进程间通信
LPCTSTR lpName, // form: \\.\pipe\pipename,not case sensitive
DWORD dwOpenMode, // PIPE_ACCESS_DUPLEX(双向的),余下的都是单向的
DWORD dwPipeMode, // PIPE_TYPE_BYTE|PIPE_READMODE_BYTE :表示以字节流的形式
DWORD nMaxInstances, // 1~255,always 1
DWORD nOutBufferSize, // 0
DWORD nInBufferSize, // 0
DWORD nDefaultTimeOut,// 毫秒
LPSECURITY_ATTRIBUTES lpSecurityAttributes // NULL
);
BOOL WINAPI WaitNamedPipe( // 客户端判断服务端的命名管道是否可以Connect
LPCTSTR lpNamedPipeName, // form: \\.\pipe\pipename
DWORD nTimeOut // NMPWAIT_WAIT_FOREVER,NMPWAIT_USE_DEFAULT_WAIT(见上),单位毫秒
);
// 这个函数返回FALSE且GetLastError()!=ERROR_IO_PENDING时才表示失败!
BOOL WINAPI ConnectNamedPipe( // 名字取得不太好,实际上类似与listen
HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped // 如果不为0应使用一个人工重置的事件对象关联到Overlapped结构,并传进来
);
BOOL WINAPI DisconnectNamedPipe(
HANDLE hNamedPipe
);
string GetConsoleResultFromCMD(const char* szCmd) {
if (!szCmd || *szCmd==0) return "";
BOOL ret = FALSE;
HANDLE hChildWrite, hParentRead;
// 使用系统默认的安全描述符,子进程可继承父进程所创建的管道句柄
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
ret = CreatePipe(&hParentRead, &hChildWrite, &sa, 0); if (!ret) return "";
STARTUPINFO si = {sizeof(STARTUPINFO)};
GetStartupInfo(&si); // 获取当前进程的startupinfo
si.wShowWindow = SW_HIDE; // CREATE_NO_WINDOW,时不必指明
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput= hChildWrite;
// 创建子进程
PROCESS_INFORMATION pi;
char szTemp[1024] = {0};
sprintf(szTemp,"C:\\Windows\\System32\\cmd.exe /c %s", szCmd);
ret = CreateProcess(NULL,szTemp,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi);
if (!ret) {
printf("CreateProcess error: %d\n", GetLastError());
CloseHandle(hChildWrite);
CloseHandle(hParentRead);
return "";
}
CloseHandle(hChildWrite); // 必须关闭pipe的write端,否则下面的ReadFile会一直阻塞!
DWORD dwExitCode;
DWORD dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
if (dwRet != WAIT_OBJECT_0 && !GetExitCodeProcess(pi.hProcess, &dwExitCode)) {
CloseHandle(hChildWrite);
CloseHandle(hParentRead);
return "";
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
string sRes("");
char buffer[1024] = {0};
DWORD bytesRead;
while (ReadFile(hParentRead,buffer,1023,&bytesRead,NULL) && bytesRead>0) {
sRes += buffer;
Sleep(80);
}
CloseHandle(hParentRead);
return sRes;
}
Mailslot
油槽: Mailslot基于UDP的广播
CreateMailslot("\\\\.\\mailslot\\MyMS", 0, MAILSLOT_WAIT_FOREVER, NULL); // Server端,创建油槽
ReadFile(hMail, buf, len, &dwReaded, NULL); // Server端,读取数据
// Client端,打开油槽
CreateFile("\\\\.\\mailslot\\MyMS", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Client端,广播数据
WriteFile(hMail, buf, len, &dwWrited, NULL);
// WM_COPYDATA
typedef struct COPYDATASTRUCT {
ULONG_PTR dwData; // 0
DWORD cb_data; // lpData内存区域的字节数
PVOID lpData; // 待发送的数据
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// send :该消息只能由SendMessage发送,因为系统必须管理用以传递数据的缓冲区的生命期
CString sendData;
GetDlgItemText(IDC_EDIT_SEND,sendData);
COPYDATASTRUCT cds = { 0, sendData.GetLength(), sendData.GetBuffer() };
SendMessage(FindWindow(NULL,"Receiver")/*目标窗口*/,WM_COPYDATA,(WPARAM)GetSafeHwnd()/*原窗口句柄*/,(LPARAM)&cds);
sendData.ReleaseBuffer();
// recv :如果接受进程处理该消息应当返回TRUE,否则返回FALSE
BOOL CReceiverDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) {
if (pCopyDataStruct->cbData > 0) {
char recvData[256] = { 0 };
strncpy(recvData, (char*)pCopyDataStruct->lpData, pCopyDataStruct->cbData);
SetDlgItemText(IDC_EDIT_RECEIVE, (char*)recvData);
Feedback(pWnd);
}
return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}
RegisterWindowMessage
注册一个系统内唯一的消息,返回值: 0xC000~0xFFFF
UINT WM_MYWMSG = ::RegisterWindowMessage("MyFirstWindowMessage");
virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult); //重载该函数,或者-->
afx_msg void OnRegisterMsg1(WPARAM wParam, LPARAM lParam);
ON_REGISTERED_MESSAGE(WM_MYWMSG, OnRegisterMsg1)
memory map
- Windows的内存映射和共享内存是统一在同一组API中.Linux有专门的内存映射与共享内存API;
- file mapping:将硬盘上的文件映射到进程的虚拟地址空间(View).读写文件便无需通过IO,直接读写内存,效率高;
- 还可以在进程间共享数据,把要映射的文件句柄写为0xFFFFFFFF.
- 文件映射依赖于系统的分页机制!windows内存颗粒度一般为64KB.
- http://www.cnblogs.com/alonezooo/articles/1530493.html
// 创建文件映射对象,可以比文件小,也可以比文件大
HANDLE CreateFileMapping( //返回映射对象的句柄
HANDLE hFile, // CreateFile创建的待映射的文件;进程间通讯时HANDLE=0xFFFFFFFF
LPSECURITY_ATTRIBUTES lpAttributes, // NULL:返回的句柄不能够被继承
DWORD flProtect, // PAGE_READWRITE,将要被映射到View的空间应该具有什么保护属性
DWORD dwMaximumSizeHigh, // 映射大小最大值的高32位,一般为0
DWORD dwMaximumSizeLow, // 低32位,0:文件当前大小,如果要给当前文件附加数据,可以更大些
LPCTSTR lpName // 映射对象的名称,可以为NULL;进程间通讯时如指定"hello"
);
// 打开其他进程创建的虚拟文件映射HANDLE(0xFFFFFFFF)
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // FILE_MAP_READ
BOOL bInheritHandle, // FALSE
LPCTSTR lpName // "hello"
);
// 将内存映射对象全部或部分映射到View,一个映射对象可以映射几个View
LPVOID MapViewOfFile( // 映射对象 --> View,返回在view中的位置;失败时返回NULL
HANDLE hFileMappingObject, // 上面返回的映射对象
DWORD dwDesiredAccess, // FILE_MAP_WRITE FILE_MAP_ALL_ACCESS
DWORD dwFileOffsetHigh, // 映射文件偏移指针的字节数,必须是内存颗粒度的整数倍64K
DWORD dwFileOffsetLow, // 低32位.大文件可以指定从多少字节处开始映射!
SIZE_T dwNumberOfBytesToMap //待映射到View的字节数,0:上面的位移处到文件尾
);
BOOL FlushViewOfFile( // View --> Disk,数据会被立即写回到磁盘
LPCVOID lpBaseAddress, // 需要写会磁盘的起始位置
SIZE_T dwNumberOfBytesToFlush // 0:整个view都写会去
);
BOOL UnmapViewOfFile( //隐含调用FlushViewOfFile()
LPCVOID lpBaseAddress //MapViewOfFile()的返回值
);
// 内存颗粒度
SYSTEM_INFO::dwAllocationGranularity;
// 获得uuid
#include <objbase.h>
#pragma comment(lib, "ole32.lib")
char uuid[37] = {0};
GUID guid;
CoCreateGuid(&guid);
snprintf(uuid, sizeof(uuid),
"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
(unsigned int)guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
#include <rpc.h>
#pragma comment(lib, "rpcrt4.lib")
UuidCreateSequential(&uuid);
RPC_CSTR rpc_str;
UuidToStringA(&uuid, &rpc_str);
std::string result = (char*)(rpc_str);
RpcStringFreeA(&rpc_str);
#include <time.h>
#include <stdlib.h>
void guid4(char *guidStr/*36chars*/) {
char *pGuidStr = guidStr;
int i = 0;
srand((unsigned int)(time(NULL)));
/*Data1 - 8 characters.*/
//*pGuidStr++ = '{';
for (i=0; i<8; i++,pGuidStr++)
((*pGuidStr = (rand() % 16)) < 10) ? *pGuidStr += 48 : *pGuidStr += 55;
/*Data2 - 4 characters.*/
*pGuidStr++ = '-';
for (i=0; i<4; i++,pGuidStr++)
((*pGuidStr = (rand() % 16)) < 10) ? *pGuidStr += 48 : *pGuidStr += 55;
/*Data3 - 4 characters.*/
*pGuidStr++ = '-';
for (i=0; i<4; i++,pGuidStr++)
((*pGuidStr = (rand() % 16)) < 10) ? *pGuidStr += 48 : *pGuidStr += 55;
/*Data4 - 4 characters.*/
*pGuidStr++ = '-';
for (i=0; i<4; i++,pGuidStr++)
((*pGuidStr = (rand() % 16)) < 10) ? *pGuidStr += 48 : *pGuidStr += 55;
/*Data5 - 12 characters.*/
*pGuidStr++ = '-';
for (i=0; i<12; i++,pGuidStr++)
((*pGuidStr = (rand() % 16)) < 10) ? *pGuidStr += 48 : *pGuidStr += 55;
//*pGuidStr++ = '}';
*pGuidStr = '\0';
}