(孙鑫 十七)进程间通信

来源:互联网 发布:英语口语录音软件 编辑:程序博客网 时间:2024/05/22 13:55
1.进程间通信的四种方式·剪贴板·匿名管道·命名管道·邮槽2.新建一个MFC EXE工程,ClipBoard Dialog based。  删除默认控件,添加两个编辑框 IDC_EDIT_RECV,IDC_EDIT_SEND,再添加两个按钮IDC_BTN_SEND,IDC_BTN_RECV。CWnd::OpenClipboardBOOL OpenClipboard( );RemarksOpens the Clipboard. Other applications will not be able to modify the Clipboard until the CloseClipboard Windows function is called. &&&The current CWnd object will not become the owner of the Clipboard until the EmptyClipboard Windows function is called.The EmptyClipboard function empties the clipboard and frees handles to data in the clipboard. The function then assigns ownership of the clipboard to the window that currently has the clipboard open. BOOL EmptyClipboard(VOID)RemarksBefore calling EmptyClipboard, an application must open the clipboard by using the OpenClipboard function. If the application specifies a NULL window handle when opening the clipboard, EmptyClipboard succeeds but sets the clipboard owner to NULL.The SetClipboardData function places data on the clipboard in a specified clipboard format. The window must be the current clipboard owner, and the application must have called the OpenClipboard function. (When responding to the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages, the clipboard owner must not call OpenClipboard before calling SetClipboardData.) HANDLE SetClipboardData(  UINT uFormat, // clipboard format  HANDLE hMem   // data handle);Allocates the specified number of bytes from the heap.Note  The global functions have greater overhead and provide fewer features than other memory management functions. New applications should use the heap functions unless documentation states that a global function should be used. For more information, see Global and Local Functions.SyntaxHGLOBAL WINAPI GlobalAlloc(  __in  UINT uFlags,//如GHND GMEM_FIXED GMEM_MOVEABLE(这里用MOVEABLE)  __in  SIZE_T dwBytes);The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block. This function is provided only for compatibility with 16-bit versions of Windows. LPVOID GlobalLock(  HGLOBAL hMem   // handle to the global memory object);  双击发送按钮:if(OpenClipboard()){CString str;HANDLE hClip;char *pBuf;EmptyClipboard();GetDlgItemText(IDC_EDIT_SEND,str);hClip=GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);  //分配全局存储器pBuf=(char*)GlobalLock(hClip);strcpy(pBuf,str);GlobalUnlock(hClip);SetClipboardData(CF_TEXT,hClip);CloseClipboard();}The GetClipboardData function retrieves data from the clipboard in a specified format. The clipboard must have been opened previously. HANDLE GetClipboardData(//返回剪贴板句柄  UINT uFormat   // clipboard format);The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format. BOOL IsClipboardFormatAvailable(//判断是否为指定的剪贴板格式  UINT format   // clipboard format);  编写接收端:if(OpenClipboard()){if(IsClipboardFormatAvailable(CF_TEXT)){HANDLE hClip;char* pBuf;hClip=GetClipboardData(CF_TEXT);pBuf=(char*)GlobalLock(hClip);GlobalUnlock(hClip); //锁定的全局存储器不能移动或丢弃SetDlgItemText(IDC_EDIT_RECV,pBuf);CloseClipboard();}}3.管道通信The CreatePipe function creates an anonymous匿名 pipe, and returns handles to the read and write ends of the pipe. BOOL CreatePipe(  PHANDLE hReadPipe,                       // pointer to read handle  PHANDLE hWritePipe,                      // pointer to write handle  LPSECURITY_ATTRIBUTES lpPipeAttributes,  // pointer to security attributes  DWORD nSize                              // pipe size 缓冲区大小,0就用缺省的缓冲区大小);The SECURITY_ATTRIBUTES structure contains the security descriptor for an object and specifies whether the handle retrieved by specifying this structure is inheritable. typedef struct _SECURITY_ATTRIBUTES { // sa     DWORD  nLength; //字节数    LPVOID lpSecurityDescriptor; //安全描述符的指针    BOOL   bInheritHandle;  //指定返回句柄是否被继承(创建新进程的时候)} SECURITY_ATTRIBUTES; 新建一个MFC EXE工程 Parent,单文档应用程序。增加一个菜单,匿名管道:创建管道IDM_PIPE_CREATE;读取数据IDM_PIPE_READ,写入数据IDM_PIPE_WRITE.给三个菜单项添加命令响应。  在view类增加成员变量HANDLE hRead private;HANDLE hWrite private,在view的构造函数中初始化为NULL。  在析构函数中判断然后删除:if(hRead)CloseHandle(hRead);if(hWrite)CloseHandle(hWrite);  在OnPipeCreate命令响应函数中:if(!CreatePipe(&hRead,&hWrite,&sa,0)){MessageBox("创建匿名管道失败!");return;}The CreateProcess function creates a new process and its primary thread. The new process executes the specified executable file. BOOL CreateProcess(  LPCTSTR lpApplicationName,                         // pointer to name of executable module要加上扩展名  LPTSTR lpCommandLine,  // pointer to command line string若找不到,则系统自动从相关路径寻址  LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes进程安全属性  LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes线程安全属性  BOOL bInheritHandles,  // handle inheritance flag继承  DWORD dwCreationFlags, // creation flags  LPVOID lpEnvironment,  // pointer to new environment block  LPCTSTR lpCurrentDirectory,   // pointer to current directory name子进程的完整路径,NULL则同父进程一样  LPSTARTUPINFO lpStartupInfo,  // pointer to STARTUPINFO新进程的主窗体如何出现  LPPROCESS_INFORMATION lpProcessInformation  // pointer to PROCESS_INFORMATION);typedef struct _STARTUPINFO { // si     DWORD   cb;  //结构体大小    LPTSTR  lpReserved;     LPTSTR  lpDesktop;     LPTSTR  lpTitle;     DWORD   dwX;     DWORD   dwY;     DWORD   dwXSize;     DWORD   dwYSize;     DWORD   dwXCountChars;     DWORD   dwYCountChars;     DWORD   dwFillAttribute;     DWORD   dwFlags;     WORD    wShowWindow;     WORD    cbReserved2;     LPBYTE  lpReserved2;     HANDLE  hStdInput;     HANDLE  hStdOutput;     HANDLE  hStdError; } STARTUPINFO, *LPSTARTUPINFO; typedef struct _PROCESS_INFORMATION { // pi     HANDLE hProcess;     HANDLE hThread;     DWORD dwProcessId;     DWORD dwThreadId; } PROCESS_INFORMATION;The GetStdHandle function returns a handle for the standard input, standard output, or standard error device. HANDLE GetStdHandle(  DWORD nStdHandle   // input, output, or error device);   //STD_INPUT_HANDLE、STD_OUTPUT_HANDLE、STD_ERROR_HANDLE  在后面添加:STARTUPINFO sui;PROCESS_INFORMATION pi;ZeroMemory(&sui,sizeof(STARTUPINFO));sui.cb=sizeof(STARTUPINFO);sui.dwFlags=STARTF_USESTDHANDLES;sui.hStdInput=hRead;sui.hStdOutput=hWrite;sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);if(!CreateProcess("..\\Child\\Debug\\Child.exe",NULL,NULL,NULL,TRUE,0,NULL,NULL,&sui,&pi)){CloseHandle(hRead);CloseHandle(hWrite);hRead=NULL;hWrite=NULL;MessageBox("创建子进程失败!");return;}else{CloseHandle(pi.hProcess);//让内核对象的使用计数减1CloseHandle(pi.hThread);//除非对内核对象的所有引用都已关闭,否则该对象不会实际删除 }The ReadFile function reads data from a file, starting at the position indicated by the file pointer. After the read operation has been completed, the file pointer is adjusted by the number of bytes actually read, unless the file handle is created with the overlapped attribute. If the file handle is created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the read operation. BOOL ReadFile(  HANDLE hFile,                // handle of file to read  LPVOID lpBuffer,             // pointer to buffer that receives data  DWORD nNumberOfBytesToRead,  // number of bytes to read  LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read  LPOVERLAPPED lpOverlapped    // pointer to structure for data);  在OnPipeRead命令响应函数中读取:char Buf[100];DWORD dwRead;if(!ReadFile(hRead,Buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(Buf);  在OnPipeWrite命令响应函数中写入:char Buf[]="http://www.baidu.com";DWORD dwWrite;if(!WriteFile(hWrite,Buf,strlen(Buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}4.子进程程序  新加一个MFC的Chile 单文档 程序到本工作空间,增加一个菜单 匿名管道:读取数据 IDM_PIPE_READ;写入数据 IDM_PIPE_WRITE,给他们添加命令响应。  给view类添加一个虚函数OnInitialUpdate,它是view类窗口完全创建后第一个调用的函数。  再给view类增加两个成员变量HANDLE hRead private和HANDLE hWrite private。然后在构造函数中初始化,在析构函数中删除。hRead=NULL;hWrite=NULL;if(hRead)CloseHandle(hRead);if(hWrite)CloseHandle(hWrite);  在OnInitialUpdate函数中获取读写句柄:hRead=GetStdHandle(STD_INPUT_HANDLE);hWrite=GetStdHandle(STD_OUTPUT_HANDLE);  再在读取和写入的命令响应中复制父窗口程序的响应代码:读取:char Buf[100];DWORD dwRead;if(!ReadFile(hRead,Buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(Buf);写入:char Buf[]="匿名管道测试程序";DWORD dwWrite;if(!WriteFile(hWrite,Buf,strlen(Buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}  匿名进程只能在父子进程间传递消息。这种关系只能是一个进程用CreateProcess去启动另一个子进程。貌似只能写一次读一次(读完数据就没有了),再读就不响应了。5.命名管道命名管道是通过网络来完成进程间的通信,它屏蔽了底层的网络协议细节。我们在不了解网络协议的情况下,也可以利用命名管道来实现进程间的通信。命名管道充分利用了Windows NT和Windows 2000内建的安全机制。将命名管道作为一种网络编程方案时,它实际上建立了一个客户机/服务器通信体系,并在其中可靠地传输数据。命名管道是围绕Windows文件系统设计的一种机制,采用“命名管道文件系统(Named Pipe File System,NPFS)”接口,因此,客户机和服务器可利用标准的Win32文件系统函数(例如:ReadFile和WriteFile)来进行数据的收发。命名管道服务器和客户机的区别在于:服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。而客户机只能同一个现成的命名管道服务器建立连接。命名管道服务器只能在Windows NT或Windows 2000上创建,所以,我们无法在两台Windows 95或Windows 98计算机之间利用管道进行通信。不过,客户机可以是Windows 95或Windows 98计算机,与Windows NT或Windows 2000计算机进行连接通信。命名管道提供了两种基本通信模式:字节模式和消息模式。在字节模式中,数据以一个连续的字节流的形式,在客户机和服务器之间流动。而在消息模式中,客户机和服务器则通过一系列不连续的数据单位,进行数据的收发,每次在管道上发出了一条消息后,它必须作为一条完整的消息读入。The CreateNamedPipe function creates an instance of a named pipe and returns a handle for subsequent pipe operations. A named pipe server process uses this function either to create the first instance of a specific named pipe and establish its basic attributes or to create a new instance of an existing named pipe. HANDLE CreateNamedPipe(  LPCTSTR lpName,         // pointer to pipe name必须形式:\\.\pipe\pipename  DWORD dwOpenMode,       // pipe open mode  DWORD dwPipeMode,       // pipe-specific modes  DWORD nMaxInstances,    // maximum number of instances创建一个实例,连接一个客户端  DWORD nOutBufferSize,   // output buffer size, in bytes  DWORD nInBufferSize,    // input buffer size, in bytes  DWORD nDefaultTimeOut,  // time-out time, in milliseconds缺省的超时值  LPSECURITY_ATTRIBUTES lpSecurityAttributes  // pointer to security attributes);//创建第一个实例及其基本属性或创建一个已存在的命名管道 新的实例。dwOpenMode:PIPE_ACCESS_DUBLEX两部分的,双向的,CS都可读写;INBOUND让客户输入,OUTBOUND向客户输出。  FILE_FLAG_WRITE_THROUGH/FILE_FLAG_OVERLAPPED同时执行的耗时的操作可立即返回,然后在后台执行。dwPipeMode:PIPE_TYPE_BYTE默认/PIPE_TYPE_MESSAGE/PIPE_WAIT默认/NOWAIT新建一个 MFC NamedPipe 单文档;新建一个菜单 命名管道:创建管道IDM_PIPE_CREATE;读取数据IDM_PIPE_READ;写入数据IDM_PIPE_WRITE,分别添加命令响应。  给VIEW类增加一个成员变量HANDLE hPipe private保存命名管道的实例句柄。然后在构造函数中初始化,在析构函数中删除:构造:hPipe=NULL;析构;if(hPipe)CloseHandle(hPipe);  然后在创建管道的命令响应中:hPipe=CreateNamedPipe("\\\\.\\pipe\\Mypipe",PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,0,1,1024,1024,0,NULL);//程序中\\相当于输出一个\,最后一个NULL创建默认的安全属性,不能被继承if(INVALID_HANDLE_VALUE==hPipe){MessageBox("创建命名管道失败!");hPipe=NULL;return;}  若创建成功了,就可以等待客户来连接。The ConnectNamedPipe function enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. A client process connects by calling either the CreateFile or CallNamedPipe function. BOOL ConnectNamedPipe(  HANDLE hNamedPipe,          // handle to named pipe to connect  LPOVERLAPPED lpOverlapped   // pointer to overlapped structure);//若创建的管道是FILE_FLAG_OVERLAPPED,且lpOverlapped不是NULL,则lpOverlapped指向的OVERLAPPED结构体需要包含一个人工重置的事件对象句柄(服务端可用CreateEvent创建)The CreateEvent function creates a named or unnamed event object. HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes,                      // pointer to security attributes  BOOL bManualReset,  // flag for manual-reset event  BOOL bInitialState, // flag for initial state  LPCTSTR lpName      // pointer to event-object name);在后面添加:HANDLE hEvent;hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);if(!hEvent){MessageBox("创建事件对象失败!");CloseHandle(hPipe);hPipe=NULL;return;}OVERLAPPED ovlap;ZeroMemory(&ovlap,sizeof(OVERLAPPED)); ovlap.hEvent=hEvent;if(!ConnectNamedPipe(hPipe,&ovlap)){if(ERROR_IO_PENDING!=GetLastError())  //pending未定的{MessageBox("等待客户端连接失败!");CloseHandle(hPipe);CloseHanlde(hEvent);hPipe=NULL;return;}}if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE)){MessageBox("等待对象失败!");CloseHandle(hPipe);CloseHandle(hEvent);hPipe=NULL;return;}CloseHandle(hEvent);  然后复制读取写入数据的代码:(注意读写的句柄改为hPipe)读取:char Buf[100];DWORD dwRead;if(!ReadFile(hPipe,Buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");return;}MessageBox(Buf);写入:char Buf[]="命名管道测试程序";DWORD dwWrite;if(!WriteFile(hPipe,Buf,strlen(Buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");return;}增加一个工程到工作区间 MFC NamedPipeClient 单文档,增加一个菜单 命名管道:连接管道 IDM_PIPE_CONNECT;读取数据 IDM_PIPE_READ;写入数据IDM_PIPE_WRITE,分别添加命令响应。增加一个HANDLE hPipe private。在构造函数中初始化,在析构函数中关闭句柄。  The WaitNamedPipe function waits until either a time-out interval elapses or an instance of the specified named pipe is available to be connected to (that is, the pipe's server process has a pending ConnectNamedPipe operation on the pipe).&&&BOOL WaitNamedPipe(  LPCTSTR lpNamedPipeName,  // pointer to name of pipe for which to wait   DWORD nTimeOut            // time-out interval, in milliseconds);lpNamedPipeName:\\servername\pipe\pipename nTimeOut:NMPWAIT_WAIT_FOREVER  在连接管道中编写:if(!WaitNamedPipe("\\\\.\\pipe\\Mypipe",NMPWAIT_WAIT_FOREVER)){MessageBox("当前没有可利用的命名管道实例!");return;}The CreateFile function creates or opens the following objects and returns a handle that can be used to access the object:files pipes mailslots communications resources disk devices consoles directoriesHANDLE CreateFile(  LPCTSTR lpFileName,          // pointer to name of the file  DWORD dwDesiredAccess,       // access (read-write) mode  DWORD dwShareMode,           // share mode  LPSECURITY_ATTRIBUTES lpSecurityAttributes,                               // pointer to security attributes  DWORD dwCreationDisposition,  // how to create  DWORD dwFlagsAndAttributes,  // file attributes  HANDLE hTemplateFile         // handle to file with attributes to                                // copy);hPipe=CreateFile("\\\\.\\pipe\\Mypipe",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(INVALID_HANDLE_VALUE==hPipe)//注意上面都是双斜杠{MessageBox("打开命名管道失败!");hPipe=NULL;return;}  然后复制读写数据的代码,然后服务器和客户端就可向对方发送数据,也可接收对方数据了。6)油槽邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。邮槽是一种单向通信机制,创建邮槽的服务器进程读取数据,打开邮槽的客户机进程写入数据。&&为保证邮槽在各种Windows平台下都能够正常工作,我们传输消息的时候,应将消息的长度限制在424字节以下。&&The CreateMailslot function creates a mailslot with the specified name and returns a handle that a mailslot server can use to perform operations on the mailslot. The mailslot is local to the computer that creates it. An error occurs if a mailslot with the specified name already exists. HANDLE CreateMailslot(  LPCTSTR lpName,         // pointer to string for mailslot name  DWORD nMaxMessageSize,  // maximum message size为0就可为任意大小  DWORD lReadTimeout,     // milliseconds before read time-out读取超时值  LPSECURITY_ATTRIBUTES lpSecurityAttributes                           // pointer to security structure);lpName:\\.\mailslot\[path]name新建一个工程 MFC MailSlotSrv 单文档:添加一个菜单 接收数据:IDM_MAILSLOT_RECV 接收数据,添加命令响应://服务器只能接收数据  HANDLE hMailSlot;hMailSlot=CreateMailslot("\\\\.\\mailslot\\MyMailslot",0,MAILSLOT_WAIT_FOREVER,NULL);if(INVALID_HANDLE_VALUE==hMailSlot){MessageBox("创建油槽失败!");return;}char Buf[100];DWORD dwRead;if(!ReadFile(hMailSlot,Buf,100,&dwRead,NULL)){MessageBox("读取数据失败!");CloseHandle(hMailSlot);return;}MessageBox(Buf);CloseHandle(hMailSlot);增加一个新的工程到工作区,MFC MailSlotClt单文档程序,增加一个菜单 发送数据:发送数据IDM_MAILSLOT_SEND,添加命令响应:HANDLE hMailSlot;hMailSlot=CreateFile("\\\\.\\mailslot\\MyMailslot",GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(INVALID_HANDLE_VALUE==hMailSlot){MessageBox("打开油槽失败!");return;}char Buf[]="油槽测试程序";DWORD dwWrite;if(!WriteFile(hMailSlot,Buf,strlen(Buf)+1,&dwWrite,NULL)){MessageBox("写入数据失败!");CloseHandle(hMailSlot);return;}CloseHandle(hMailSlot);  注意上面命名管道以及油槽的命名的时候\\.\中的.若不是本地主机则应该设置为服务器主机名。&&&
0 0
原创粉丝点击