Windows命名管道实现一对多进程通信 [C++实现]

场景描述

  • 服务端负责接收和读取,有两个进程先后向管道内写入数据
  • 这里的一对多是一个服务端有顺序的服务多个进程,实质上是有先后顺序的一对一
  • 流程图:
    进程1写入后,Sleep() 3秒钟。创建进程2,再次写入,进程2退出。进程1再次写入。

代码实现

// Process.h
#pragma once
#include<iostream>
#include<windows.h>
#define BuffSize 1024
#define pipeName "\\\\.\\pipe\\consolePipe"
using namespace std;

class Process {
public:
	HANDLE hPipe = INVALID_HANDLE_VALUE;
	unsigned long writeLength = 0, readLength = 0;

	Process() {}

	int createNewProcess(const char* fileName) { 
		STARTUPINFO si;
		PROCESS_INFORMATION pi;
		ZeroMemory(&pi, sizeof(pi));
		ZeroMemory(&si, sizeof(si));

		int flag = 0;
		flag = CreateProcess(fileName, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
		if (flag == 0) {
			cout << "create process error:  " << GetLastError() << endl;
			return -1;
		}
		return 0; 
	}

	int initPipe() { 
		hPipe = CreateNamedPipe(pipeName,
			PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
			PIPE_TYPE_BYTE,
			1,
			BuffSize, BuffSize,
			0, NULL
			);
		if (hPipe == INVALID_HANDLE_VALUE) {
			cout << "server create Pipe error: " << GetLastError() << endl;
			return -1;
		}
		return 0; 
	}

	int serverConnPipe() { 
		int flag = ConnectNamedPipe( hPipe, NULL);
        // 第二个参数设为NULL,阻塞执行,否则会出现链接问题
		if (flag == 0) {
			flag = GetLastError();
			if (flag != ERROR_IO_PENDING) {
				cout << "server Pipe connect error: " << GetLastError() << endl;
			}
			return -1;
		}
		return 0; 
	}

	int disConnect() { 
		if(hPipe != INVALID_HANDLE_VALUE)
			DisconnectNamedPipe(hPipe);
		return 0; 
	}

	int clientConnPipe() {
		int flag = WaitNamedPipe(pipeName, NMPWAIT_WAIT_FOREVER);
		if (flag == 0)
			cout << "client Pipe wait failed: " << GetLastError() << endl;
		hPipe = CreateFile(pipeName,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
			);

		if (hPipe == INVALID_HANDLE_VALUE) {
			cout << "client create Pipe error: " << GetLastError() << endl;
			hPipe = NULL;
			return -1;
		}
		return 0;
	}

	int wPipe(const char* s) { 
		int flag = WriteFile( hPipe, s, strlen(s)+1, &writeLength, NULL);
		if (flag == 0)
			cout << "写入失败: " << GetLastError() << endl;
		else
			cout << "写入成功\n";
		return 0; 
	}

	int rPipe(char* buff) { 
		memset(buff, NULL, BuffSize);
		int flag = ReadFile(hPipe, buff, BuffSize, &readLength, NULL);
		if (flag == 0) {
			cout << "read pipe error: " << GetLastError() << endl;
			return -1;
		}
		return 0; 
	}

};

其中,ConnectNamedPipe需要阻塞执行,不然会出现链接错误

// server.cpp
#include"Process.h"
#include<iostream>

int main() {
	Process proc;
	char buff[1024];
	proc.initPipe();
	while (true) {
		int flag = proc.serverConnPipe();
		if(flag == 0)
			flag = proc.rPipe(buff);
		if (flag == 0) {
			cout << buff;
		    proc.disConnect();
		}
	}
	return 0;
}

通过循环执行ConnectNamedPipe和disconnectNamedPipe实现一对多,但实质上,服务端一次只能接受一个进程的数据,这里的一对多其实是有先后顺序的一对一

// client.cpp
// 进程1
#include"Process.h"
#include<iostream>

int main() {
	Process proc;
	proc.clientConnPipe();
	proc.wPipe("进程1写入管道\n");
	cout << "进程1执行结束" << endl;
	proc.disConnect();
	proc.createNewProcess("C:\\文件绝对路径\\Client2.exe");

	Sleep(3000); // 通过Sleep掌控进程写入管道的先后顺序
	proc.clientConnPipe();
	proc.wPipe("进程1再次写入管道\n");
	proc.disConnect();
	getchar();
	return 0;
}
// Client2.cpp Clinet2.exe
// 进程2
#include"Process.h"
#include<iostream>

int main() {
    Process proc;
	proc.clientConnPipe();
	proc.wPipe("进程2写入管道\n");
	proc.disConnect();
}
  • 执行结果:
    执行一次Server.cpp,执行两次Client.cpp

参考博文

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Windows 中,可以使用命名管道(Named Pipes)实现进程间通信。以下是一些基本步骤: 1. 创建命名管道 使用 CreateNamedPipe 函数创建一个命名管道。该函数需要指定管道名称、管道的读写模式、管道的最大实例数等参数。 2. 等待客户端连接 使用 ConnectNamedPipe 函数等待客户端的连接。该函数会一直阻塞,直到有客户端连接成功。 3. 接收客户端数据 使用 ReadFile 函数从管道中读取客户端发送的数据。 4. 发送数据给客户端 使用 WriteFile 函数向管道中写入数据,以便客户端读取。 5. 断开连接 使用 DisconnectNamedPipe 函数断开与客户端的连接。如果需要与多个客户端通信,则返回第 2 步。 6. 关闭管道 使用 CloseHandle 函数关闭命名管道的句柄。 注意事项: - 在创建管道时,需要指定管道名称,该名称在系统中必须是唯一的。 - 管道支持同步和异步方式进行读写操作,可以根据具体需求选择使用哪种方式。 - 管道的读写操作是阻塞式的,也可以使用 overlapped 结构体实现异步操作。 下面是一个简单的代码示例,演示如何使用命名管道实现进程间通信: ``` #include <windows.h> #include <stdio.h> #define PIPE_NAME "\\\\.\\pipe\\MyPipe" int main() { HANDLE hPipe; char buffer[1024]; DWORD dwRead; // 创建命名管道 hPipe = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE) { printf("CreateNamedPipe failed! Error code: %d\n", GetLastError()); return 1; } // 等待客户端连接 if (!ConnectNamedPipe(hPipe, NULL)) { printf("ConnectNamedPipe failed! Error code: %d\n", GetLastError()); return 1; } // 接收客户端数据 if (!ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL)) { printf("ReadFile failed! Error code: %d\n", GetLastError()); return 1; } printf("Received data from client: %s\n", buffer); // 发送数据给客户端 if (!WriteFile(hPipe, "Hello, client!", 15, NULL, NULL)) { printf("WriteFile failed! Error code: %d\n", GetLastError()); return 1; } // 断开连接 DisconnectNamedPipe(hPipe); // 关闭管道 CloseHandle(hPipe); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值