当前位置:首页 >> 编程开发 >> Visual C++ >> 内容

c++通道应用(服务器篇)

时间:2015/5/19 21:33:15 作者:平凡之路 来源:xuhantao.com 浏览:

【C++程序中命名管道通讯的实现】

最近学习c++中,试手过程选择实 现一个程序与被注入程序互通的工具,感觉如果是计算机本地的通讯使用socket 似乎有些不太理性,俗话说“杀鸡焉牛宰牛刀”,所以使用伟大的 google找到了更适合轻量级程序通讯的内容,即下面所要说的:“管道 ”。

首先按照国际管理,介绍下c++实现“管道” 的几 个核心函数;

CreateNamedPipe(        //服务器端创建 并命名一个管道,服务器端通过提供管道名与其进行通讯
  LPCTSTR lpName, // 管道名称
  DWORD dwOpenMode, // 管道打开模式
  DWORD dwPipeMode, // 管道的其他模式定义
  DWORD nMaxInstances, // 这个管道能够创建的最大实例数量 。必须是1到常数PIPE_UNLIMITED_INSTANCES间的一个值。它对于管道的所有实 例来说都应是相同的
  DWORD nOutBufferSize, // 建议的输出缓冲区长度;零表示 用默认设置
  DWORD nInBufferSize, //  建议的输入缓冲区长度;零表示 用默认设置
  DWORD nDefaultTimeOut, // 管道的默认等待超时。对一个管 道的所有实例来说都应相同
  LPSECURITY_ATTRIBUTES lpSecurityAttributes // pointer to security attributes
  )

详细参数请见:http:  //vbworld.sxnw.gov.cn/vbapi/detail/CreateNamedPipe.htm

C onnectNamedPipe( //指示一台服务器等待下去,直至客户机同一个命名管道连 接
  HANDLE handle, //管道的句柄
      lpOverlapped OVERLAPPED  //如设为NULL(传递 ByVal As Long),表示将线程挂起,直到一个客户同管道连接为止。否则就立 即返回;此时,如管道尚未连接,客户同管道连接时就会触发lpOverlapped结构 中的事件对象。随后,可用一个等待函数来监视连接
  )

详细参数请见:http:  //vbworld.sxnw.gov.cn/vbapi/detail/ConnectNamedPipe.htm

WaitNamedPipe(        //由一个客户进程调用,等候一个管道变成可 用状态
  LPCTSTR lpNamedPipeName, //指定要连接的管道名称
  DWORD nTimeOut //超时设定
  )

详细参数请见:http:  //vbworld.sxnw.gov.cn/vbapi/detail/WaitNamedPipe.htm CreateFile(
  LPCTSTR lpFileName, //指向文件名的指针,如果是写入到管 道当中,则写入管道名
    DWORD dwDesiredAccess, //访问模式(写/读)
    DWORD dwShareMode, //共享模式
    LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向 安全属性的指针
    DWORD dwCreationDisposition, //如何创建
    DWORD dwFlagsAndAttributes, //文件属性
    HANDLE hTemplateFile //用于复制文件句柄
  )

详细参数请见:http://baike.baidu.com/view/1288759.htm

WriteFile( //用于向 管道中写入内容
  HANDLE hFile, // 文件句柄,通过CreateFile创建的句柄
    LPCVOID lpBuffer, // 数据缓存区指针
    DWORD nNumberOfBytesToWrite, // 你要写的字节数
    LPDWORD lpNumberOfBytesWritten, // 用于保存实际写 入字节数的存储区域的指针
    LPOVERLAPPED lpOverlapped // OVERLAPPED结构体指针
  )

详细参数请见:http://baike.baidu.com/view/1295782.htm ReadFile(     //用于读取管道中以写入的信息
  HANDLE hFile, //文件的句柄
    LPVOID lpBuffer, //用于保存读入数据的一个缓冲区
    DWORD nNumberOfBytesToRead, //要读入的字符数
    LPDWORD lpNumberOfBytesRead, //指向实际读取字节数 的指针
    LPOVERLAPPED lpOverlapped //如文件打开时指定了 FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。该结构定 义了一次异步读取操作。否则,应将这个参数设为NULL
 )

详细参数请见:http://baike.baidu.com/view/1336847.htm。行了,假设看这篇文章的同学都已经 了VS2005下MFC的创建和使用,下面的内容将开始实刀实枪的开始“管道之 旅”,使用MFC创建一个标准的管道通讯程序。

【server部分:】

1、为了更好的控制我们的程序,第一步定义一个管道基类是个好的做法 ,在这里我们借鉴一个例子,创建一个"CMyPipe.h"的头文件,代码 如下:

#pragma once
class CMyPipe //创建我们的通道基类,主要为了方便定位通道
{
public:
 CMyPipe(); //创建一个构造函数;
 CMyPipe(LPCTSTR lpctstr); //构造函数的重载;
 ~CMyPipe(); //一个析构函数;

protected:
 HANDLE MyPipe; //创建一个HANDLE 变量,用于定义我们的通道 头
 CString MyPipeName; //创建一个通道名;
};

2、定义一个基类CMyPipe的扩展类CPipeServer ,将其写入到一个新的头文件中,在这里我命名为pp.h,代码如下:

#pragma once
#include "CMyPipe.h"
class CPipeServer:public CMyPipe //定义基类CMyPipe的扩展 类
{
public: //构造函数
 CPipeServer();
 CPipeServer(LPCTSTR lpPipeName); //构造函数重载
 ~CPipeServer(); //析构函数
 CWnd* GethWndServer(); //定义一个获取窗口函数
 CWnd* SethWndServer(CWnd *pWndServer); //定义设置窗口的 函数
 bool ServerReplyInfo(CString StrReply); //定义创建通道反 馈信息的函数
 bool ServerExit(); //服务器退出时使用
 static UINT ServerReadProc(LPVOID lParam); //管道服务器 创建后的操作,创建服务器可不是让他闲着。。。
 void InitPipeServer(UINT InstanceCount);
 void UnInitPipeServer(void);
 CPipeServer *m_pPipeServer; //CPipeServer类动态数组(可实 现多个管道实例,提高管道服务器端负荷处理能力)
 UINT m_InstanceCount; //管道实例个数
private:
 CWnd* m_pWndServer; //定义将要写入的窗口类变量
 CWinThread *m_pWinThread; //每次使用新线程调用服务器时的 存储线程变量
 CString m_StrReply; //接收的信息存储变量
};

3、接下来我们将对之前定义的函数在项目中的 cpp文件中进行实例化,并做应用:

//3个CMyPipe基类的实例化


CMyPipe::CMyPipe()//直接定义管道名
{
 MyPipeName=_T("\\\\.\\pipe\\snmp");
}
CMyPipe::CMyPipe(LPCTSTR lpPipeName)  //管道名的重载
{
 MyPipeName=lpPipeName;
}
::CMyPipe::~CMyPipe()
{
 MyPipeName.Empty();
}
CPipeServer::CPipeServer():CMyPipe()
{
 m_StrReply.Empty();
 m_pWndServer=NULL;
}
CPipeServer::CPipeServer(LPCTSTR lpPipeName):CMyPipe (lpPipeName)
{
 m_StrReply.Empty();
 m_pWndServer=NULL;
}
CPipeServer::~CPipeServer()
{
 m_StrReply.Empty();
 m_pWndServer=NULL;
}
//因为涉及到了新建线程接收管道信息,所以需要定位控件窗口
CWnd * CPipeServer::SethWndServer(CWnd *pWndServer)
{
 return m_pWndServer=pWndServer;
}
CWnd* CPipeServer::GethWndServer()
{
 return m_pWndServer;
}
//定位控件窗口

void CPipeServer::InitPipeServer(UINT InstanceCount)
{
    m_pPipeServer=NULL;
    m_InstanceCount=0;
    m_pPipeServer=new CPipeServer[InstanceCount];
    if(m_pPipeServer!=NULL)
        m_InstanceCount=InstanceCount;
}
void CPipeServer::UnInitPipeServer(void)
{
    if(m_pPipeServer!=NULL){
        delete [] m_pPipeServer;
        m_pPipeServer=NULL;
        m_InstanceCount=0;
    }
}

//定义创建通道反馈信息的函数
bool CPipeServer::ServerReplyInfo(CString StrReply)
{
 bool IsSuc=false;
 MyPipe=CreateNamedPipe(MyPipeName,
  PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
  PIPE_TYPE_BYTE|PIPE_WAIT,
  PIPE_UNLIMITED_INSTANCES,
  256,
  256,
  NULL, //NMPWAIT_USE_DEFAULT_WAIT,
  NULL);
 if (MyPipe!=INVALID_HANDLE_VALUE)
 {
  m_StrReply=StrReply;
  IsSuc=true;
  m_pWinThread=AfxBeginThread(ServerReadProc,(LPVOID) this);
 }
 return IsSuc;
}
//定义创建通道反馈信息的函数
//定义服务器退出时的操作
bool CPipeServer::ServerExit()
{
 bool IsSuc=false;
 HANDLE hFile;
 TCHAR buffer[256];
 DWORD dwNumberOfBytesWritten;
 WaitNamedPipe(MyPipeName,NMPWAIT_WAIT_FOREVER);
 hFile=CreateFile (MyPipeName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRIT E,
                     NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_ARCHIVE|FILE_FLAG_WRITE_THROUGH,NULL   );
 if(hFile==INVALID_HANDLE_VALUE)
 {
  return IsSuc;
 }
 _stprintf(buffer,_T("exit"));
 if (WriteFile(hFile,buffer,(_tcslen(buffer)+1)*sizeof (TCHAR),&dwNumberOfBytesWritten,NULL))
 {
  IsSuc=true;
 }
 CloseHandle(hFile);
 return IsSuc;
}
//定义服务器退出时的操作


//服务器读取并处理信息
UINT CPipeServer::ServerReadProc(LPVOID lParam)
{
 CPipeServer * pPipeServer=(CPipeServer*)lParam;
 DWORD dwNumberOfBytesRead,dwNumberOfBytesWritten;
 TCHAR buffer[256];
 while(ConnectNamedPipe(pPipeServer->MyPipe,NULL))
 {
  while(ReadFile(pPipeServer- >MyPipe,buffer,256*sizeof(TCHAR),&dwNumberOfBytesRead,NULL))
  {
   if(dwNumberOfBytesRead==0) break;
   if(_tcscmp(buffer,_T("exit"))==0)
   {
    DisconnectNamedPipe(pPipeServer->MyPipe);
                CloseHandle(pPipeServer- >MyPipe);
                return 0;
   }
   if(pPipeServer->m_pWndServer!=NULL)
   {
    ((CListBox*)pPipeServer->m_pWndServer- >GetDlgItem(IDC_LBCONTENT))->InsertString(0,buffer);
   }
   _tcscpy(buffer,pPipeServer->m_StrReply);
   WriteFile(pPipeServer->MyPipe,buffer,(_tcslen (buffer)+1)*sizeof(TCHAR),&dwNumberOfBytesWritten,NULL);
  }
  DisconnectNamedPipe(pPipeServer->MyPipe); //管道服务 器断开该实例的连接
 }
 CloseHandle(pPipeServer->MyPipe); //关闭实例句柄
    return 0;

}
//服务器读取并处理信息


//使用一个ID为IDC_BTNCONNECT的Button控件控制服务器开启/关 闭,并使用一个ID为IDC_BTNCONNECT的combo box的控件显示服务器端显示的信 息。
void CaccDlg::OnBnClickedBtnconnect()
{
  CPipeServer * pPipeServer=(CPipeServer*)this;
     CString MyCaption;
     GetDlgItem(IDC_BTNCONNECT)->GetWindowText (MyCaption);
     UINT i;
     if(MyCaption.Compare(_T("连接"))==0) {
         for(i=0;i<pPipeServer- >m_InstanceCount;i++){
    pPipeServer->m_pPipeServer->SethWndServer (this);
             pPipeServer->m_pPipeServer- >ServerReplyInfo(_T("服务器应答!"));
         }
         GetDlgItem(IDC_BTNCONNECT)- >SetWindowText(_T("断开"));
     }
     else{
         for(i=0;i<pPipeServer- >m_InstanceCount;i++)
             pPipeServer->m_pPipeServer- >ServerExit();
         GetDlgItem(IDC_BTNCONNECT)- >SetWindowText(_T("连接"));
     }
}

OK,按F5执行试一下……

是 不是有句提示:“CaccDlg”: 不是类或命名空间名称

哈哈 ,说明你照抄了上面的那段OnBnClickedBtnconnect()的代码,请把 “CaccDlg”改成你所制作的项目的Dlg名。

相关文章
  • 没有相关文章
  • 徐汉涛(www.xuhantao.com) © 2024 版权所有 All Rights Reserved.
  • 部分内容来自网络,如有侵权请联系站长尽快处理 站长QQ:965898558(广告及站内业务受理) 网站备案号:蒙ICP备15000590号-1