使用异步命名管道通信的实例

记录一个使用异步命名管道通信的实例。代码参考了 MSDN 的文档:使用完成例程的命名管道服务器 - Win32 apps | Microsoft Learn。

服务端代码

#include <windows.h> 
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
#define MAX_USERNAME_LEN 100
#define MAX_PASSWORD_LEN 100typedef struct
{OVERLAPPED oOverlap;HANDLE hPipeInst;struct Message {TCHAR username[MAX_USERNAME_LEN];TCHAR password[MAX_PASSWORD_LEN];TCHAR request[BUFSIZE];} message;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 _tmain(VOID)
{HANDLE hConnectEvent;OVERLAPPED oConnect;LPPIPEINST lpPipeInst;DWORD dwWait, cbRet;BOOL fSuccess, fPendingIO;// Create one event object for the connect operation. hConnectEvent = CreateEvent(NULL,    // default security attributeTRUE,    // manual reset event TRUE,    // initial state = signaled NULL);   // unnamed event object if (hConnectEvent == NULL){printf("CreateEvent failed with %d.\n", GetLastError());return 0;}oConnect.hEvent = hConnectEvent;// Call a subroutine to create one instance, and wait for // the client to connect. fPendingIO = CreateAndConnectInstance(&oConnect);while (1){// Wait for a client to connect, or for a read or write // operation to be completed, which causes a completion // routine to be queued for execution. dwWait = WaitForSingleObjectEx(hConnectEvent,  // event object to wait for INFINITE,       // waits indefinitely TRUE);          // alertable wait enabled switch (dwWait){// The wait conditions are satisfied by a completed connect // operation. case 0:// If an operation is pending, get the result of the // connect operation. if (fPendingIO){fSuccess = GetOverlappedResult(hPipe,     // pipe handle &oConnect, // OVERLAPPED structure &cbRet,    // bytes transferred FALSE);    // does not wait if (!fSuccess){printf("ConnectNamedPipe (%d)\n", GetLastError());return 0;}}// Allocate storage for this instance. lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST));if (lpPipeInst == NULL){printf("GlobalAlloc failed (%d)\n", GetLastError());return 0;}lpPipeInst->hPipeInst = hPipe;// Start the read operation for this client. // Note that this same routine is later used as a // completion routine after a write operation. lpPipeInst->cbToWrite = 0;CompletedWriteRoutine(0, 0, (LPOVERLAPPED)lpPipeInst);// Create new pipe instance for the next client. fPendingIO = CreateAndConnectInstance(&oConnect);break;// The wait is satisfied by a completed read or write // operation. This allows the system to execute the // completion routine. case WAIT_IO_COMPLETION:break;// An error occurred in the wait function. default:{printf("WaitForSingleObjectEx (%d)\n", GetLastError());return 0;}}}return 0;
}// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED) 
// This routine is called as a completion routine after writing to 
// the pipe, or when a new client has connected to a pipe instance.
// It starts another read operation. VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten,LPOVERLAPPED lpOverLap)
{LPPIPEINST lpPipeInst;BOOL fRead = FALSE;// lpOverlap points to storage for this instance. lpPipeInst = (LPPIPEINST)lpOverLap;// The write operation has finished, so read the next request (if // there is no error). if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))fRead = ReadFileEx(lpPipeInst->hPipeInst,&lpPipeInst->message,sizeof(lpPipeInst->message),(LPOVERLAPPED)lpPipeInst,(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine);// Disconnect if an error occurred. if (!fRead)DisconnectAndClose(lpPipeInst);
}// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED) 
// This routine is called as an I/O completion routine after reading 
// a request from the client. It gets data and writes it to the pipe. VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,LPOVERLAPPED lpOverLap)
{LPPIPEINST lpPipeInst;BOOL fWrite = FALSE;// lpOverlap points to storage for this instance. lpPipeInst = (LPPIPEINST)lpOverLap;// The read operation has finished, so write a response (if no // error occurred). if ((dwErr == 0) && (cbBytesRead != 0)){GetAnswerToRequest(lpPipeInst);if (lpPipeInst->cbToWrite == 0){return;}fWrite = WriteFileEx(lpPipeInst->hPipeInst,lpPipeInst->chReply,lpPipeInst->cbToWrite,(LPOVERLAPPED)lpPipeInst,(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);}// Disconnect if an error occurred. if (!fWrite)DisconnectAndClose(lpPipeInst);
}// DisconnectAndClose(LPPIPEINST) 
// This routine is called when an error occurs or the client closes 
// its handle to the pipe. VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
{// Disconnect the pipe instance. if (!DisconnectNamedPipe(lpPipeInst->hPipeInst)){printf("DisconnectNamedPipe failed with %d.\n", GetLastError());}// Close the handle to the pipe instance. CloseHandle(lpPipeInst->hPipeInst);// Release the storage for the pipe instance. if (lpPipeInst != NULL)GlobalFree(lpPipeInst);
}// CreateAndConnectInstance(LPOVERLAPPED) 
// This function creates a pipe instance and connects to the client. 
// It returns TRUE if the connect operation is pending, and FALSE if 
// the connection has been completed. BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
{LPCTSTR lpszPipename = L"\\\\.\\pipe\\mynamedpipe";hPipe = CreateNamedPipe(lpszPipename,             // pipe name PIPE_ACCESS_DUPLEX |      // read/write access FILE_FLAG_OVERLAPPED,     // overlapped mode PIPE_TYPE_MESSAGE |       // message-type pipe PIPE_READMODE_MESSAGE |   // message read mode PIPE_WAIT,                // blocking mode PIPE_UNLIMITED_INSTANCES, // unlimited instances BUFSIZE * sizeof(TCHAR),    // output buffer size BUFSIZE * sizeof(TCHAR),    // input buffer size PIPE_TIMEOUT,             // client time-out NULL);                    // default security attributesif (hPipe == INVALID_HANDLE_VALUE){printf("CreateNamedPipe failed with %d.\n", GetLastError());return 0;}// Call a subroutine to connect to the new client. return ConnectToNewClient(hPipe, lpoOverlap);
}BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
{BOOL fConnected, fPendingIO = FALSE;// Start an overlapped connection for this pipe instance. fConnected = ConnectNamedPipe(hPipe, lpo);// Overlapped ConnectNamedPipe should return zero. if (fConnected){printf("ConnectNamedPipe failed with %d.\n", GetLastError());return 0;}switch (GetLastError()){// The overlapped connection in progress. case ERROR_IO_PENDING:fPendingIO = TRUE;break;// Client is already connected, so signal an event. case ERROR_PIPE_CONNECTED:if (SetEvent(lpo->hEvent))break;// If an error occurs during the connect operation... default:{printf("ConnectNamedPipe failed with %d.\n", GetLastError());return 0;}}return fPendingIO;
}BOOL AuthenticateClient(LPPIPEINST lpPipeInst) {// 硬编码的用户名和密码列表const TCHAR* validUsernames[] = { TEXT("WMsgClientName") };const TCHAR* validPasswords[] = { TEXT("WMsgClientPassword") };// 从 lpPipeInst 中获取客户端发送的身份验证信息(例如,用户名和密码)TCHAR username[MAX_USERNAME_LEN];TCHAR password[MAX_PASSWORD_LEN];TCHAR request[BUFSIZE];// 解析客户端发送的身份验证信息lstrcpy(username, lpPipeInst->message.username);lstrcpy(password, lpPipeInst->message.password);lstrcpy(request, lpPipeInst->message.request);// 检查用户名和密码是否在有效的用户名和密码列表中for (int i = 0; i < sizeof(validUsernames) / sizeof(validUsernames[0]); i++) {if (_tcscmp(username, validUsernames[i]) == 0 && _tcscmp(password, validPasswords[i]) == 0) {// 用户名和密码匹配,身份验证成功// 将余下的请求部分复制到 lpPipeInst->chRequest 中lstrcpy(lpPipeInst->message.request, request);// 设置请求长度lpPipeInst->cbRead = (lstrlen(lpPipeInst->message.request) + 1) * sizeof(TCHAR);return TRUE;}}// 如果用户名和密码不匹配任何有效的用户名和密码,身份验证失败_tprintf(TEXT("Invalid authentication.\n"));return FALSE;
}VOID GetAnswerToRequest(LPPIPEINST pipe)
{_tprintf(TEXT("ClientMsg:[0x%I64X] %s\n"), (UINT64)pipe->hPipeInst, pipe->message.request);// 验证客户端身份if (!AuthenticateClient(pipe)){pipe->cbToWrite = 0;DisconnectAndClose(pipe);return;}_tprintf(TEXT("Client authentication completed.\n"));// 根据客户端发送的不同消息生成不同的回复if (_tcscmp(pipe->message.request, TEXT("Request1")) == 0){StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Response to Request1"));}else if (_tcscmp(pipe->message.request, TEXT("Request2")) == 0){StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Response to Request2"));}else{StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Default answer from server"));}pipe->cbToWrite = (lstrlen(pipe->chReply) + 1) * sizeof(TCHAR);
}

客户端代码

#include <windows.h> 
#include <stdio.h>
#include <conio.h>
#include <tchar.h>#define BUFSIZE 512typedef struct
{TCHAR username[100];TCHAR password[100];TCHAR request[BUFSIZE];
} Message;int _tmain(int argc, TCHAR* argv[])
{HANDLE hPipe;Message message;BOOL   fSuccess = FALSE;DWORD  cbRead, cbToWrite, cbWritten, dwMode;LPCTSTR lpszPipename = L"\\\\.\\pipe\\mynamedpipe";// 初始化结构体信息_tcscpy_s(message.username, _T("WMsgClientName"));_tcscpy_s(message.password, _T("WMsgClientPassword"));if (argc > 1)_tcscpy_s(message.request, argv[1]);else_tcscpy_s(message.request, _T("Default request from client."));// 尝试打开命名管道while (1){hPipe = CreateFile(lpszPipename,   // pipe name GENERIC_READ |  // read and write access GENERIC_WRITE,0,              // no sharing NULL,           // default security attributesOPEN_EXISTING,  // opens existing pipe 0,              // default attributes NULL);          // no template file // 如果管道句柄有效,则退出循环if (hPipe != INVALID_HANDLE_VALUE)break;// 如果错误不是 ERROR_PIPE_BUSY,则退出程序if (GetLastError() != ERROR_PIPE_BUSY){_tprintf(TEXT("Could not open pipe. GLE=%d\n"), GetLastError());return -1;}// 如果所有管道实例都在忙,则等待 20 秒if (!WaitNamedPipe(lpszPipename, 20000)){printf("Could not open pipe: 20 second wait timed out.");return -1;}}// 设置管道模式为消息读取模式dwMode = PIPE_READMODE_MESSAGE;fSuccess = SetNamedPipeHandleState(hPipe,    // 管道句柄 &dwMode,  // 新的管道模式 NULL,     // 不设置最大字节数 NULL);    // 不设置最大时间 if (!fSuccess){_tprintf(TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError());return -1;}// 向管道服务器发送消息cbToWrite = sizeof(message);_tprintf(TEXT("Sending %d byte message: \"%s\"\n"), cbToWrite, message.request);fSuccess = WriteFile(hPipe,                  // 管道句柄 &message,               // 消息 cbToWrite,              // 消息长度 &cbWritten,             // 写入的字节数 NULL);                  // 不使用重叠if (!fSuccess){_tprintf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError());return -1;}printf("\nMessage sent to server, receiving reply as follows:\n");// 从管道读取服务器的回复fSuccess = ReadFile(hPipe,    // 管道句柄 message.request, // 用于接收回复的缓冲区 BUFSIZE * sizeof(TCHAR),  // 缓冲区大小 &cbRead,  // 读取的字节数 NULL);    // 不使用重叠if (!fSuccess){_tprintf(TEXT("ReadFile from pipe failed. GLE=%d\n"), GetLastError());return -1;}_tprintf(TEXT("Server's reply: \"%s\"\n"), message.request);printf("\n<End of message, press ENTER to terminate connection and exit>");_getch();CloseHandle(hPipe);return 0;
}

测试结果


发布于:2024.02.08,更新于:2024.02.08. 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/460111.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

containerd中文翻译系列(十五)转运服务

传输服务是一种简单灵活的服务&#xff0c;可用于在源和目的地之间传输人工制品对象。灵活的应用程序接口&#xff08;API&#xff09;允许传输接口的每个实施方案决定是否可以在源和目的地之间进行传输。这样&#xff0c;实现者就可以直接添加新功能&#xff0c;而无需对应用程…

高斯伪谱C++封装库开源!

Windows x64/86 C无依赖运行高斯伪谱法求解最优控制问题&#xff0c;你只需要ElegantGP! Author: Y. F. Zhang His Github: https://github.com/ZYunfeii 写在前面 这个库在你下载它的那一时刻起不再依赖任何其他代码&#xff0c;直接可用来构建C的最优控制问题并进行求解。…

机器学习--K-近邻算法常见的几种距离算法详解

文章目录 距离度量1 欧式距离(Euclidean Distance)2 曼哈顿距离(Manhattan Distance)3 切比雪夫距离 (Chebyshev Distance)4 闵可夫斯基距离(Minkowski Distance)5 标准化欧氏距离 (Standardized EuclideanDistance)6 余弦距离(Cosine Distance)7 汉明距离(Hamming Distance)【…

一起玩儿物联网人工智能小车(ESP32)——57. SPI总线协议初探(一)

摘要&#xff1a;介绍SPI总线的基本知识 前面已经学习过IIC总线协议&#xff0c;今天开始介绍另一个总线协议——SPI。SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是由Motorola提出的一种高速、全双工、同步的通信总线。并且在芯片的管脚…

防静电地板行业研究:市场需求不断的扩大

防静电地板又叫做耗散静电地板&#xff0c;是一种地板&#xff0c;当它接地或连接到任何较低电位点时&#xff0c;使电荷能够耗散&#xff0c;以电阻在10的5次方到10的9次方欧姆之间为特征。 目前防静电地板产业还没有集中完成规模化&#xff0c;标准化&#xff0c;规范化&…

c++阶梯之类与对象(中)< 续集 >

前文&#xff1a; c阶梯之类与对象&#xff08;上&#xff09;-CSDN博客 c阶梯之类与对象&#xff08;中&#xff09;-CSDN博客 前言&#xff1a; 在上文中&#xff0c;我们学习了类的六个默认成员函数之构造&#xff0c;析构与拷贝构造函数&#xff0c;接下来我们来看看剩下…

堆排序-Python实现

简述 堆排序&#xff08;Heap Sort&#xff09;是一种基于比较的排序算法&#xff0c;它利用堆这种数据结构所设计的一种排序算法。堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。 堆 堆排…

【数据结构】链表OJ面试题4(题库+解析)

1.前言 前五题在这http://t.csdnimg.cn/UeggB 后三题在这http://t.csdnimg.cn/gbohQ 给定一个链表&#xff0c;判断链表中是否有环。http://t.csdnimg.cn/Rcdyc 记录每天的刷题&#xff0c;继续坚持&#xff01; 2.OJ题目训练 10. 给定一个链表&#xff0c;返回链表开始…

豪掷770亿!华为员工集体“分红大狂欢”:至少14万人受益

豪掷770亿&#xff01;华为员工集体“分红大狂欢”&#xff1a;至少14万人受益 近日&#xff0c;华为宣布了其2023年度分红计划&#xff0c;总金额高达770.85亿元&#xff0c;预计至少将惠及14万员工。这一消息引发了广泛关注和热议&#xff0c;成为业界的一大亮点。作为中国领…

嵌入式学习之Linux入门篇笔记——16,Linux工具之make工具和makefile文件

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 1.什么是 make 工具&#xff1f; 编译辅助工具。解决使用命令…

【漏洞复现】EasyCVR智能边缘网关用户信息泄漏漏洞

Nx01 产品简介 EasyCVR智能边缘网关是一种基于边缘计算和人工智能技术的设备&#xff0c;旨在提供高效的视频监控和智能分析解决方案。它结合了视频监控摄像头、计算能力和网络连接&#xff0c;能够在现场进行视频数据处理和分析&#xff0c;减轻对中心服务器的依赖。 Nx02 漏…

【代理模式】

定义&#xff1a;代理模式是一种结构型设计模式&#xff0c;它允许我们创建一个代理对象&#xff0c;用于控制对另一个对象的访问。 代理对象充当了被代理对象&#xff08;目标对象&#xff09;的代表&#xff0c;与被代理对象实现相同的接口&#xff0c;从而实现对被代理对象…