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.csdn.net/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 
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页