同一局域网内Pipe管道通信
代码借鉴
https://www.cnblogs.com/cxq0017/p/6525027.html
服务端
NamePipeServer.h
#ifndef NAME_PIPE_SERVER_H
#define NAME_PIPE_SERVER_H
#include<windows.h>
#include<iostream>
class NamePipeServer
{
public:
NamePipeServer()
{
pStr = "data from server";
pPipeName = "\\\\.\\pipe\\testPipe";
}
//创建命名管道
void CreateNamedPipeInServer();
//从命名管道中读取数据
void NamedPipeReadInServer();
//往命名管道中写入数据
void NamedPipeWriteInServer();
private:
HANDLE hNamedPipe;
const char *pStr;
const char *pPipeName;
};
#endif
NamePipeServer.cpp
#include "stdafx.h"
#include "NamePipeServer.h"
using namespace std;
void NamePipeServer::CreateNamedPipeInServer()
{
HANDLE hEvent;
OVERLAPPED ovlpd;
BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = &sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, (PACL) 0, FALSE);
//创建命名管道
//这里创建的是双向模式且使用重叠模式(异步操作)的命名管道
hNamedPipe = CreateNamedPipe( L"\\\\.\\pipe\\testspipe",PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,0, 1, 1024, 1024, 0, &sa);
if( INVALID_HANDLE_VALUE == hNamedPipe )
{
cout << GetLastError() << endl;
hNamedPipe = NULL;
cout << "创建命名管道失败!!!" << endl << endl;
return;
}
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if( !hEvent )
{
cout<<"创建事件失败 ..."<< endl<< endl;
return;
}
memset(&ovlpd, 0, sizeof(OVERLAPPED));
ovlpd.hEvent = hEvent;
cout << "等待客户端的连接" << endl;
if( !ConnectNamedPipe(hNamedPipe, &ovlpd) )
{
if( ERROR_IO_PENDING != GetLastError() )
{
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
cout<<"等待客户端连接失败 ..."<< endl << endl;
return;
}
}
//等待事件 hEvent 失败
if( WAIT_FAILED == WaitForSingleObject(hEvent, INFINITE) )
{
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
cout<<"等待对象失败 ..."<<endl<<endl;
return;
}
CloseHandle(hEvent);
}
void NamePipeServer::NamedPipeReadInServer()
{
char * pReadBuf;
DWORD dwRead;
pReadBuf = new char[strlen(pStr) + 1];
memset(pReadBuf, 0, strlen(pStr) + 1);
//从命名管道中读取数据
if( !ReadFile(hNamedPipe, pReadBuf, strlen(pStr), &dwRead, NULL) )
{
delete []pReadBuf;
cout<<"读取数据失败 ..."<< endl<< endl;
return;
}
cout << "读取数据成功::"<< pReadBuf << endl<< endl;
}
void NamePipeServer::NamedPipeWriteInServer()
{
DWORD dwWrite;
//向命名管道中写入数据
if( !WriteFile(hNamedPipe, pStr, strlen(pStr), &dwWrite, NULL) )
{
cout << "写入数据失败 ..." << endl<< endl;
return;
}
cout << "写入数据成功:: "<< pStr<< endl<< endl;
}
int main()
{
NamePipeServer pipeserver;
//创建命名管道
pipeserver.CreateNamedPipeInServer();
//从命名管道读数据
pipeserver.NamedPipeReadInServer();
//向匿名管道中写入数据
pipeserver.NamedPipeWriteInServer();
system("pause");
return 0;
}
客户端
NamePipeClient.h
#ifndef _NAME_PIPE_CLIENT_H
#define _NAME_PIPE_CLIENT_H
#include<windows.h>
#include<iostream>
class NamePipeClient
{
public:
NamePipeClient()
{
pStr = "data from client";
pPipeName = "\\\\.\\pipe\\testPipe";
}
//打开命名管道
void OpenNamedPipeInClient();
//客户端从命名管道中读取数据
void NamedPipeReadInClient();
//客户端往命名管道中写入数据
void NamedPipeWriteInClient();
private:
//用来保存在客户端通过 CreateFile 打开的命名管道句柄HANDLE
HANDLE hNamedPipe;
const char * pStr;
const char * pPipeName;
};
#endif
NamePipeClient.cpp
#include "stdafx.h"
#include "NamePipeClient.h"
using namespace std;
void NamePipeClient::OpenNamedPipeInClient()
{
//等待连接命名管道
if( !WaitNamedPipe(L"\\\\.\\pipe\\testspipe", NMPWAIT_WAIT_FOREVER) )
{
cout<<"命名管道实例不存在 ..."<< endl<< endl;
return;
}
cout << "成功连接到服务器" << endl;
//打开命名管道
hNamedPipe = CreateFile( L"\\\\.\\pipe\\testspipe", GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if( INVALID_HANDLE_VALUE == hNamedPipe )
{
cout << "打开命名管道失败!!!" << endl << endl;
return;
}
}
void NamePipeClient::NamedPipeReadInClient()
{
char * pReadBuf;
DWORD dwRead;
pReadBuf = new char[strlen(pStr) + 1];
memset(pReadBuf, 0, strlen(pStr) + 1);
//从命名管道中读取数据
if( !ReadFile(hNamedPipe, pReadBuf, strlen(pStr), &dwRead, NULL) )
{
delete []pReadBuf;
cout << "读取数据失败 ..."<< endl << endl;
return;
}
cout<<"读取数据成功:: "<< pReadBuf << endl << endl;
}
void NamePipeClient::NamedPipeWriteInClient()
{
DWORD dwWrite;
//向命名管道中写入数据
if( !WriteFile(hNamedPipe, pStr, strlen(pStr), &dwWrite, NULL) )
{
cout<<"写入数据失败 ..." << endl << endl;
return;
}
cout<< "写入数据成功:: "<< pStr << endl << endl;
}
int main()
{
NamePipeClient pipeclient;
pipeclient.OpenNamedPipeInClient();
//往命名管道中写入数据
pipeclient.NamedPipeWriteInClient();
//接收从服务器发来的数据
pipeclient.NamedPipeReadInClient();
system("pause");
return 0;
}
VS内的项目
创建一个命名管道的多个实例,就需要多次调用CreateNamedPipe函数,参数 lpName 为一个字符串,其格式必须为 \.\pipe\pipeName,其中圆点 ”.” 表示的是本地机器,如果想要与远程的服务器建立连接,那么这个圆点位置处应指定这个远程服务器的名称,而其中的 “pipe” 这个是个固定的字符串,也就是说不能进行改变的,最后的 “pipename” 则代表的是我将要创建的命名管道的名称了,参数 dwOpenMode 用来指定管道的访问方式,重叠方式,写直通方式,还有管道句柄的安全访问方式。
pipeName in Server
由于Server端先创建管道,所以Server端的参数 lpName 为 \.\pipe\pipeName
pipeName in Client
由Server端创建管道后,Client链接,所以Client端的参数 lpName 为 \主机名\pipe\pipeName,只是做测试或者其他内容,上面的代码默认即可
如果是建立同一局域网内的Pipe通信,其中主机名可以为IP也可以为计算机名,我选择用IP
共需要修改3处
Client的头文件1处
Pipe链接
VS成功编译后,有两个有效的exe
顺序是先启动服务器NamePipeServer.exe
显示服务器在等待客户端的连接
然后在启动客户端(虚拟机中/同一个机器)
可以看到服务器成功从客户端读取到数据,并且写入数据成功。
而客户端也写入服务器数据成功,并且成功读取到服务器的数据。
同一局域网内的Pipe通信
排错参考https://bbs.youkuaiyun.com/topics/310203566
我出现的问题是客户端连不上服务端创建的管道
最后解决的办法是**“先与目标机器建立IPC连接”**
net use \\ip\ipc$ "密码" /user:"用户名" 建立IPC非空链接
net use \\192.168.236.133\ipc$ password /user:Administrator
用完最好删除
net use \\ip\ipc$ /del 删除IPC链接
net use \\192.168.236.133\ipc$ /del