基于visual c++之windows核心编程代码分析(17)通过pipe进程间通信
56 阅读
0 评论
37 点赞
概述
管道是一种用于在进程间共享数据的机制,其实质是一段共享内存。Windows系统为这段共享的内存设计采用数据流I/0的方式来访问。由一个进程读、另一个进程写,类似于一个管道两端,因此这种进程间的通信方式称作“管道”。
管道分为匿名管道和命名管道。
匿名管道只能在父子进程间进行通信,不能在网络间通信,而且数据传输是单向的,只能一端写,另一端读。
命令管道可以在任意进程间通信,通信是双向的,任意一端都可读可写,但是在同一时间只能有一端读、一端写。
管道客户端代码实现如下
[cpp]
view plain
copy
- /* 头文件 */
- #include <windows.h>
- #include <stdio.h>
- #include <conio.h>
- #include <tchar.h>
- /* 常量 */
- #define BUFSIZE 512
- /* ************************************
- * int main(VOID)
- * 功能 pipe 通信服务端主函数
- **************************************/
- int main(int argc, TCHAR *argv[])
- {
- HANDLE hPipe;
- LPTSTR lpvMessage=TEXT("Default message from client");
- TCHAR chBuf[BUFSIZE];
- BOOL fSuccess;
- DWORD cbRead, cbWritten, dwMode;
- LPTSTR lpszPipename = TEXT("\\.\pipe\samplenamedpipe");
- if( argc > 1 ) // 如果输入了参数,则使用输入的参数
- lpvMessage = argv[1];
- while (1)
- {
- // 打开一个命名pipe
- hPipe = CreateFile(
- lpszPipename, // pipe 名
- GENERIC_READ | GENERIC_WRITE, // 可读可写
- 0, // 不共享
- NULL, // 默认安全属性
- OPEN_EXISTING, // 已经存在(由服务端创建)
- 0, // 默认属性
- NULL);
- if (hPipe != INVALID_HANDLE_VALUE)
- break;
- // 如果不是 ERROR_PIPE_BUSY 错误,直接退出
- if (GetLastError() != ERROR_PIPE_BUSY)
- {
- printf("Could not open pipe");
- return 0;
- }
- // 如果所有pipe实例都处于繁忙状态,等待2秒。
- if (!WaitNamedPipe(lpszPipename, 2000))
- {
- printf("Could not open pipe");
- return 0;
- }
- }
- // pipe已经连接,设置为消息读状态
- dwMode = PIPE_READMODE_MESSAGE;
- fSuccess = SetNamedPipeHandleState(
- hPipe, // 句柄
- &dwMode, // 新状态
- NULL, // 不设置最大缓存
- NULL); // 不设置最长时间
- if (!fSuccess)
- {
- printf("SetNamedPipeHandleState failed");
- return 0;
- }
- // 写入pipe
- fSuccess = WriteFile(
- hPipe, // 句柄
- lpvMessage, // 写入的内容
- (lstrlen(lpvMessage)+1)*sizeof(TCHAR), // 写入内容的长度
- &cbWritten, // 实际写的内容
- NULL); // 非 overlapped
- if (!fSuccess)
- {
- printf("WriteFile failed");
- return 0;
- }
- do
- {
- // 读回复
- fSuccess = ReadFile(
- hPipe, // 句柄
- chBuf, // 读取内容的缓存
- BUFSIZE*sizeof(TCHAR), // 缓存大小
- &cbRead, // 实际读的字节
- NULL); // 非 overlapped
- if (! fSuccess && GetLastError() != ERROR_MORE_DATA)
- break; //失败,退出
- _tprintf( TEXT("%sn"), chBuf ); // 打印读的结果
- } while (!fSuccess); // ERROR_MORE_DATA 或者成功则循环
- getch();//任意键退出
- // 关闭句柄
- CloseHandle(hPipe);
- return 0;
- }
管道服务端代码实现如下,
[cpp]
view plain
copy
- /* 头文件 */
- #include <windows.h>
- #include <stdio.h>
- #include <tchar.h>
- /* 常量 */
- #define PIPE_TIMEOUT 5000
- #define BUFSIZE 4096
- /* 结构定义 */
- typedef struct
- {
- OVERLAPPED oOverlap;
- HANDLE hPipeInst;
- TCHAR chRequest[BUFSIZE];
- DWORD cbRead;
- TCHAR chReply[BUFSIZE];
- DWORD cbToWrite;
- } PIPEINST, *LPPIPEINST;
- /* 函数声明 */
- VOID DisconnectAndClose(LPPIPEINST);
- BOOL CreateAndConnectInstance(LPOVERLAPPED);
- BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
- VOID GetAnswerToRequest(LPPIPEINST);
- VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
- VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
- /* 全局变量 */
- HANDLE hPipe;
- /* ************************************
- * int main(VOID)
- * 功能 pipe 通信服务端主函数
- **************************************/
- int main(VOID)
- {
- HANDLE hConnectEvent;
- OVERLAPPED oConnect;
- LPPIPEINST lpPipeInst;
- DWORD dwWait, cbRet;
- BOOL fSuccess, fPendingIO;
- // 用于连接操作的事件对象
- hConnectEvent = CreateEvent(
- NULL, // 默认属性
- TRUE, // 手工reset
- TRUE, // 初始状态 signaled
- NULL); // 未命名
- if (hConnectEvent == NULL)
- {
- printf("CreateEvent failed with %d.n", GetLastError());
- return 0;
- }
- // OVERLAPPED 事件
- oConnect.hEvent = hConnectEvent;
- // 创建连接实例,等待连接
- fPendingIO = CreateAndConnectInstance(&oConnect);
- while (1)
- {
- // 等待客户端连接或读写操作完成
- dwWait = WaitForSingleObjectEx(
- hConnectEvent, // 等待的事件
- INFINITE, // 无限等待
- TRUE);
- switch (dwWait)
- {
- case 0:
- // pending
- if (fPendingIO)
- {
- // 获取 Overlapped I/O 的结果
- fSuccess = GetOverlappedResult(
- hPipe, // pipe 句柄
- &oConnect, // OVERLAPPED 结构
- &cbRet, // 已经传送的数据量
- FALSE); // 不等待
- if (!fSuccess)
- {
- printf("ConnectNamedPipe (%d)n", GetLastError());
- return 0;
- }
- }
- // 分配内存
- lpPipeInst = (LPPIPEINST) HeapAlloc(GetProcessHeap(),0,sizeof(PIPEINST));
- if (lpPipeInst == NULL)
- {
- printf("GlobalAlloc failed (%d)n", GetLastError());
- return 0;
- }
- lpPipeInst->hPipeInst = hPipe;
- // 读和写,注意CompletedWriteRoutine和CompletedReadRoutine的相互调用
- lpPipeInst->cbToWrite = 0;
- CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst);
- // 再创建一个连接实例,以响应下一个客户端的连接
- fPendingIO = CreateAndConnectInstance(
- &oConnect);
- break;
- // 读写完成
- case WAIT_IO_COMPLETION:
- break;
- default:
- {
- printf("WaitForSingleObjectEx (%d)n", GetLastError());
- return 0;
- }
- }
- }
- return 0;
- }
- /* ************************************
- * CompletedWriteRoutine
- * 写入pipe操作的完成函数
- * 接口参见FileIOCompletionRoutine回调函数定义
- *
- * 当写操作完成时被调用,开始读另外一个客户端的请求
- **************************************/
- VOID WINAPI CompletedWriteRoutine(
- DWORD dwErr,
- DWORD cbWritten,
- LPOVERLAPPED lpOverLap)
- {
- LPPIPEINST lpPipeInst;
- BOOL fRead = FALSE;
- // 保存overlap实例
- lpPipeInst = (LPPIPEINST) lpOverLap;
- // 如果没有错误
- if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))
- {
- fRead = ReadFileEx(
- lpPipeInst->hPipeInst,
- lpPipeInst->chRequest,
- BUFSIZE*sizeof(TCHAR),
- (LPOVERLAPPED) lpPipeInst,
- // 写读操作完成后,调用CompletedReadRoutine
- (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
- }
- if (! fRead)
- // 出错,断开连接
- DisconnectAndClose(lpPipeInst);
- }
- /* ************************************
- * CompletedReadRoutine
- * 读取pipe操作的完成函数
- * 接口参见FileIOCompletionRoutine回调函数定义
- *
- * 当读操作完成时被调用,写入回复
- **************************************/
- VOID WINAPI CompletedReadRoutine(
- DWORD dwErr,
- DWORD cbBytesRead,
- LPOVERLAPPED lpOverLap)
- {
- LPPIPEINST lpPipeInst;
- BOOL fWrite = FALSE;
- // 保存overlap实例
- lpPipeInst = (LPPIPEINST) lpOverLap;
- // 如果没有错误
- if ((dwErr == 0) && (cbBytesRead != 0))
- {
- // 根据客户端的请求,生成回复
- GetAnswerToRequest(lpPipeInst);
- // 将回复写入到pipe
- fWrite = WriteFileEx(
- lpPipeInst->hPipeInst,
- lpPipeInst->chReply, //将响应写入pipe
- lpPipeInst->cbToWrite,
- (LPOVERLAPPED) lpPipeInst,
- // 写入完成后,调用CompletedWriteRoutine
- (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);
- }
- if (! fWrite)
- // 出错,断开连接
- DisconnectAndClose(lpPipeInst);
- }
- /* ************************************
- * VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
- * 功能 断开一个连接的实例
- * 参数 lpPipeInst,断开并关闭的实例句柄
- **************************************/
- VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
- {
- // 关闭连接实例
- if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) )
- {
- printf("DisconnectNamedPipe failed with %d.n", GetLastError());
- }
- // 关闭 pipe 实例的句柄
- CloseHandle(lpPipeInst->hPipeInst);
- // 释放
- if (lpPipeInst != NULL)
- HeapFree(GetProcessHeap(),0, lpPipeInst);
- }
- /* ************************************
- * BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
- * 功能 建立连接实例
- * 参数 lpoOverlap,用于overlapped IO的结构
- * 返回值 是否成功
- **************************************/
- BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
- {
- LPTSTR lpszPipename = TEXT("\\.\pipe\samplenamedpipe");
- // 创建named pipe
- hPipe = CreateNamedPipe(
- lpszPipename, // pipe 名
- PIPE_ACCESS_DUPLEX | // 可读可写
- FILE_FLAG_OVERLAPPED, // overlapped 模式
- // pipe模式
- PIPE_TYPE_MESSAGE | // 消息类型 pipe
- PIPE_READMODE_MESSAGE | // 消息读模式
- PIPE_WAIT, // 阻塞模式
- PIPE_UNLIMITED_INSTANCES, // 无限制实例
- BUFSIZE*sizeof(TCHAR), // 输出缓存大小
- BUFSIZE*sizeof(TCHAR), // 输入缓存大小
- PIPE_TIMEOUT, // 客户端超时
- NULL); // 默认安全属性
- if (hPipe == INVALID_HANDLE_VALUE)
- {
- printf("CreateNamedPipe failed with %d.n", GetLastError());
- return 0;
- }
- // 连接到新的客户端
- return ConnectToNewClient(hPipe, lpoOverlap);
- }
- /* ************************************
- * BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
- * 功能 建立连接实例
- * 参数 lpoOverlap,用于overlapped IO的结构
- * 返回值 是否成功
- **************************************/
- BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
- {
- BOOL fConnected, fPendingIO = FALSE;
- // 开始一个 overlapped 连接
- fConnected = ConnectNamedPipe(hPipe, lpo);
- if (fConnected)
- {
- printf("ConnectNamedPipe failed with %d.n", GetLastError());
- return 0;
- }
- switch (GetLastError())
- {
- // overlapped连接进行中.
- case ERROR_IO_PENDING:
- fPendingIO = TRUE;
- break;
- // 已经连接,因此Event未置位
- case ERROR_PIPE_CONNECTED:
- if (SetEvent(lpo->hEvent))
- break;
- // error
- default:
- {
- printf("ConnectNamedPipe failed with %d.n", GetLastError());
- return 0;
- }
- }
- return fPendingIO;
- }
- // TODO根据客户端的请求,给出响应
- VOID GetAnswerToRequest(LPPIPEINST pipe)
- {
- _tprintf( TEXT("[%d] %sn"), pipe->hPipeInst, pipe->chRequest);
- lstrcpyn( pipe->chReply, TEXT("Default answer from server") ,BUFSIZE);
- pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
- }
最后
以上就是英勇西装为你收集整理的基于visual c++之windows核心编程代码分析(17)通过pipe进程间通信的全部内容,希望文章能够帮你解决基于visual c++之windows核心编程代码分析(17)通过pipe进程间通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
- 本文分类:Other
- 浏览次数:56 次浏览
- 发布日期:2023-12-02 04:10:09
- 本文链接:https://www.kaopuke.com/article/k-p-k_13_u_23_o_10_f5_13__23_g1.html
发表评论 取消回复