RT,先放代码
#include <windows.h>
#include <iostream>
bool writeToPipe(HANDLE hPipe, const std::string& input) {
DWORD bytesWritten = 0;
if (!WriteFile(hPipe, input.c_str(), static_cast<DWORD>(input.length()), &bytesWritten, NULL)) {
std::cerr << "写入管道失败" << std::endl;
return false;
}
// 发送回车
const char* newline = "\r\n";
if (!WriteFile(hPipe, newline, 2, &bytesWritten, NULL)) {
std::cerr << "写入管道失败" << std::endl;
return false;
}
return true;
}
int main() {
HANDLE hOutputPipe, hInputPipe;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
// 定义一个安全属性结构
SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
saAttr.bInheritHandle = TRUE; // 允许子进程继承句柄
// 创建输出命名管道
hOutputPipe = CreateNamedPipe(
"\\\\.\\pipe\\output_pipe",
PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
10,
1024,
1024,
NMPWAIT_USE_DEFAULT_WAIT,
&saAttr // 将安全属性结构传递给CreateNamedPipe函数
);
if (hOutputPipe == INVALID_HANDLE_VALUE) {
std::cerr << "无法创建输出命名管道" << std::endl;
return 1;
}
// 创建输入命名管道
hInputPipe = CreateNamedPipe(
"\\\\.\\pipe\\input_pipe",
PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
10,
1024,
1024,
NMPWAIT_USE_DEFAULT_WAIT,
&saAttr // 将安全属性结构传递给CreateNamedPipe函数
);
if (hInputPipe == INVALID_HANDLE_VALUE) {
std::cerr << "无法创建输入命名管道" << std::endl;
CloseHandle(hOutputPipe);
return 1;
}
// 设置启动信息
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdError = hOutputPipe;
siStartInfo.hStdOutput = hOutputPipe;
siStartInfo.hStdInput = hInputPipe;
// 启动Java进程
if (!CreateProcess(
NULL,
"java -jar spigot-1.20.4.jar -nogui",
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&siStartInfo,
&piProcInfo)) {
std::cerr << "无法启动Java进程" << std::endl;
CloseHandle(hOutputPipe);
CloseHandle(hInputPipe);
return 1;
}
std::string input;
while(1)
{
std::cin>>input;
writeToPipe(hInputPipe, input);
}
// 等待子进程结束
WaitForSingleObject(pi.hProcess, INFINITE);
// 关闭进程和线程的句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
在这段代码中,我首先定义了安全属性结构saAttr,确保所有程序可以连接至管道(昨天在这里被卡了一个小时),然后创建了名为output_pipe和input_pipe的命名管道,其中output_pipe只允许服务端写入,客户端读取,input_pipe只允许客户端写入,服务端读取。然后修改siStartInfo中的启动信息,将hStdOutput绑定在管道output_pipe上,hStdInput绑定在管道input_pipe上,如下
// 设置启动信息
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdError = hOutputPipe;
siStartInfo.hStdOutput = hOutputPipe;
siStartInfo.hStdInput = hInputPipe;
然后使用CreateProcess创建新进程执行命令“java -jar spigot-1.20.4.jar -nogui”其中使用siStartInfo作为启动信息。
确保启动后,我循环从屏幕读取内容,并尝试使用writeToPipe函数将信息发送至input_pipe管道,下面是writeToPipe函数的定义
bool writeToPipe(HANDLE hPipe, const std::string& input) {
DWORD bytesWritten = 0;
if (!WriteFile(hPipe, input.c_str(), static_cast<DWORD>(input.length()), &bytesWritten, NULL)) {
std::cerr << "写入管道失败" << std::endl;
return false;
}
// 发送回车
const char* newline = "\r\n";
if (!WriteFile(hPipe, newline, 2, &bytesWritten, NULL)) {
std::cerr << "写入管道失败" << std::endl;
return false;
}
return true;
}
在尝试执行发送命令后,WriteFile函数返回错误。通过GetLastError()函数获取到了错误代码5。在微软的官方说明文档中5表示Access is denied.(拒绝访问)。意味着我无法向input_pipe写入内容。随后其编写了另一个程序判断output_pipe是否可用
#include <windows.h>
#include <bits/stdc++.h>
int main() {
HANDLE hPipe;
char buffer[1024];
DWORD bytesRead;
// 打开管道
hPipe = CreateFile(
"\\\\.\\pipe\\output_pipe", // 管道名称
GENERIC_READ, // 只读访问
0, // 不共享
NULL, // 默认安全属性
OPEN_EXISTING, // 已存在的管道
0, // 默认标志
NULL // 无模板文件
);
if (hPipe != INVALID_HANDLE_VALUE) {
while(1)
{
ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
std::cout << buffer;
std::memset(buffer,NULL,sizeof(buffer));
}
// 关闭管道
CloseHandle(hPipe);
} else {
std::cerr << "无法打开管道" << std::endl;
}
return 0;
}
程序成功接收到了output_pipe管道输出的内容,意味着管道的定义没有问题。麻烦各位帮我检查一下程序的输如有没有成功重定向到input_pipe上?如果没有,我该怎么做?