Windows下C程序通过命名管道传UINT32结构体客户端接收全零如何解决
问题根因汇总
- 服务端发送长度计算错误
你传输的是二进制结构体数据,第一个字段Height的值为0,你用strlen(msg)计算发送长度时,strlen遇到第一个0字节就会返回0,导致服务端实际上没有发送任何数据,客户端读到的就是初始化的全0缓存。 - 命名管道路径转义错误
C语言中字符串里的反斜杠需要转义,你定义的管道路径#define TestCoordinate_Pipe "\\.\pipe\TestCoordinates"实际解析出来是错误的,应该写成\\\\.\\pipe\\TestCoordinates,否则两端无法成功建立管道连接。 - 客户端返回局部变量指针(野指针)
getObjectLocation函数中buffer是栈上的局部数组,函数返回后栈空间会被回收,返回的buffer指针是野指针,main函数中用这个指针拷贝数据会读取到无效内容。 - 客户端读管道逻辑错误
你用了while (ReadFile(...))的死循环读取,会持续读直到管道断开,而且你给二进制数据末尾加\0的操作是字符串场景的用法,会破坏二进制结构体的有效数据,同时原代码未对管道句柄执行关闭操作,存在资源泄漏。
修复方案
1. 统一修改管道路径宏
两端的管道路径宏都改为正确的转义格式:
#define TestCoordinate_Pipe "\\\\.\\pipe\\TestCoordinates"
2. 修复服务端发送逻辑
把WriteFile的长度参数从strlen(msg)改为实际要发送的结构体大小sizeof(ObjectInfo):
WriteFile( hPipe, msg, sizeof(ObjectInfo), &dwWritten, NULL);
3. 修复客户端逻辑
- 不返回局部栈内存指针,改为直接传入结构体指针填充结果
- 去掉多余的读循环和加
\0的操作,只读一次需要的结构体大小即可 - 增加管道句柄关闭逻辑,避免资源泄漏
修复后的客户端参考代码:
#include <stdio.h> #include <Windows.h> #include <stdbool.h> #define TestCoordinate_Pipe "\\\\.\\pipe\\TestCoordinates" #define MESSAGE_MAX_LENGTH 1024 #pragma pack(push, 1) typedef struct _ObjectInfo { UINT32 Height; UINT32 XCoordinate; UINT32 YCoordinate; UINT32 Width; }ObjectInfo; #pragma pack(pop) bool getObjectLocation(char* pipe, ObjectInfo* outInfo) { HANDLE hPipe; char buffer[MESSAGE_MAX_LENGTH] = { 0 }; DWORD dwRead; hPipe = CreateNamedPipe( pipe, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, MESSAGE_MAX_LENGTH, MESSAGE_MAX_LENGTH, NMPWAIT_USE_DEFAULT_WAIT, NULL); if (hPipe == INVALID_HANDLE_VALUE) { return false; } if (ConnectNamedPipe(hPipe, NULL) != FALSE) { // 只读一次需要的结构体大小即可 if (ReadFile(hPipe, buffer, sizeof(ObjectInfo), &dwRead, NULL) != FALSE && dwRead == sizeof(ObjectInfo)) { RtlCopyMemory(outInfo, buffer, sizeof(ObjectInfo)); DisconnectNamedPipe(hPipe); CloseHandle(hPipe); return true; } } DisconnectNamedPipe(hPipe); CloseHandle(hPipe); return false; } int main() { ObjectInfo objectInfo = {0}; if (getObjectLocation(TestCoordinate_Pipe, &objectInfo)) { printf("\n\tHeight: %d;\t X-Coordinate: %d\t Y-Coordinate: %d\tWidth: %d", objectInfo.Height, objectInfo.XCoordinate, objectInfo.YCoordinate, objectInfo.Width); } else { printf("读取管道失败"); } return 0; }
可选优化
上述代码已经在结构体定义前后加了#pragma pack编译指令,强制1字节对齐,可以避免两端结构体对齐规则不一致导致的解析错误。
内容的提问来源于stack exchange,提问作者Ganesh Kamath - 'Code Frenzy'
相关产品推荐
相关产品推荐

