进程通信之--匿名管道双向通信

学习了m_buddy 的https://blog.csdn.net/m_buddy/article/details/72867107 Windows进程通信——匿名管道

发现建了一个匿名管道,双向通信存在问题,建了两个匿名管道

匿名管道是在本地机器上使用,实现父进程和子进程之间的通信的进程通信机制。需要注意两点:

(1)就是在本地机器上,这是因为匿名管道不支持跨网络之间的两个进程之间的通信

(2)实现的是父进程和子进程之间的通信,而不是任意的两个进程,因为需要继承父进程的读写管道句柄

 

CreatePipe()函数,它的原型为

BOOL WINAPI CreatePipe(

 __out   PHANDLE hReadPipe,    //参数 hReadPipe 为输出参数,该句柄代表管道的读取句柄。

 __out   PHANDLE hWritePipe,   //参数 hWritePipe 为输出参数,该句柄代表管道的写入句柄

 __in    LPSECURITY_ATTRIBUTES lpPipeAttributes,   //参数 lpPipeAttributes 为一个输入参数,指向一个 SECURITY_ATTRIBUTES 的结构体指针

 __in    DWORD nSize   //管道的缓存大小

 );

这里由于是父子进程的关系,需要对SECURITY_ATTRIBUTES结构体进行设置,它的原型为

typedef struct _SECURITY_ATTRIBUTES {

  DWORD  nLength;   //结构体大小

  LPVOID lpSecurityDescriptor;  //

  BOOL   bInheritHandle;    //由于是父子进程,一定要设置为True,允许继承

SECURITY_ATTRIBUTES*PSECURITY_ATTRIBUTES*LPSECURITY_ATTRIBUTES;

 

以下例子实现父子进程通过匿名管道进行双向通信:

父进程核心代码:

 

void CFatherDlg::my_PipeInit()

{

    if (!my_CreatePipe()) 

        return;

    if (!my_CreateProcess()) 

        return;

    HANDLE hThread = CreateThread(NULL0, Pipe_Listen, &m_hPipeRead2, 0NULL);    //创建socket的发送线程

    关闭该接收线程句柄,释放引用计数

    CloseHandle(hThread);

}

//************************************************************************

// 函数名称:        SetProcessInfo

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        初始化SECURITY_ATTRIBUTES结构体

// 函数参数:    PSECURITY_ATTRIBUTES & ps   需要初始化的SECURITY_ATTRIBUTES结构体

// 返 回 值:       void

//************************************************************************

void CFatherDlg::SetSecurity_attr(SECURITY_ATTRIBUTES& ps)

{

    //这里必须将 bInheritHandle 设置为 TRUE,

    //从而使得子进程可以继承父进程创建的匿名管道的句柄

    ps.bInheritHandle = TRUE;

    ps.lpSecurityDescriptor = NULL;

    ps.nLength = sizeof(SECURITY_ATTRIBUTES);

}

//************************************************************************

// 函数名称:        SetStartInfo

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        初始化STARTUPINFO结构体

// 函数参数:    STARTUPINFO & si    需要初始化的STARTUPINFO结构体

// 返 回 值:       void

//************************************************************************

void CFatherDlg::SetStartInfo(STARTUPINFO& si)

{

    memset(&si, 0sizeof(STARTUPINFO));

    si.cb = sizeof(STARTUPINFO);

    si.wShowWindow = SW_SHOW;

    si.dwFlags = STARTF_USESTDHANDLES;//STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;

    //子进程的标准输入句柄为父进程管道1的读数据句柄

    si.hStdInput = m_hPipeRead1; //子进程的标准输入

    //子进程的标准输出句柄为父进程管道2的写数据句柄

    si.hStdOutput = m_hPipeWrite2;

    //子进程的标准错误处理句柄和父进程的标准错误处理句柄一致

    si.hStdError = HANDLE(STD_ERROR_HANDLE);

}

//************************************************************************

// 函数名称:        my_CreatePipe

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        创建匿名管道

// 返 回 值:       bool

//************************************************************************

bool CFatherDlg::my_CreatePipe()

{

    SECURITY_ATTRIBUTES sa;

    SetSecurity_attr(sa);

    //创建管道1

    if (!CreatePipe(&m_hPipeRead1, &m_hPipeWrite1, &sa, 0))

    {

        MessageBox(_T("create anonymous pipe1 failed"));

        return false;

    }

    //创建管道2

    if (!CreatePipe(&m_hPipeRead2, &m_hPipeWrite2, &sa, 0))

    {

        MessageBox(_T("create anonymous pipe2 failed"));

        return false;

    }

    return true;

}

//************************************************************************

// 函数名称:        my_SendDataPipe

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        通过管道发送数据

// 函数参数:    std::string data 需要发送的数据

// 返 回 值:       void

//************************************************************************

void CFatherDlg::my_SendDataPipe(CString data)

{

    DWORD data_write;

    //写入数据

    if (!WriteFile(m_hPipeWrite1, (LPCTSTR)data, data.GetLength() * 2, &data_write, NULL))

    {

        MessageBox(_T("Father send data Failed!"));

    }

}

//************************************************************************

// 函数名称:        my_CreateProcess

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        创建进程

// 返 回 值:       bool

//************************************************************************

bool CFatherDlg::my_CreateProcess()

{

    PROCESS_INFORMATION pi = { 0 };

    STARTUPINFO si;

    SetStartInfo(si);  

    LPWSTR exe_path = _T("E:\\yebo\\study\\C&C++\\Test\\ProcessTX\\Process\\Son\\Debug\\Son.exe");

    BOOL kk = CreateProcess(exe_path, NULLNULLNULL, TRUE, NULLNULLNULL, &si, &pi);

    if (!kk)

    {

        MessageBox(_T("create process failed"));

        CloseHandle(m_hPipeWrite1); //创建进程失败,关闭读写句柄

        CloseHandle(m_hPipeRead1);

        CloseHandle(m_hPipeWrite2); //创建进程失败,关闭读写句柄

        CloseHandle(m_hPipeRead2);

        m_hPipeWrite1 = NULL;

        m_hPipeRead1 = NULL;

        m_hPipeWrite2 = NULL;

        m_hPipeRead2 = NULL;

        return false;

    }

    //由于结构体pi中的数据已经使用不到了,将其资源释放

    CloseHandle(pi.hProcess);

    CloseHandle(pi.hThread);

    return true;

}

//************************************************************************

// 函数名称:        Pipe_Listen

// 访问权限:        public 

// 创建日期:        2017/06/05

// 创 建 人:       

// 函数说明:        监听管道的数据

// 函数参数:    LPVOID lpParameter

// 返 回 值:       DWORD WINAPI

//************************************************************************

DWORD WINAPI CFatherDlg::Pipe_Listen(LPVOID lpParameter)

{

    HANDLE* PipeRead = (HANDLE*)lpParameter;

    TCHAR data[4096] = { 0 };

    DWORD data_read;

    while (true)

    {

        memset(data, 0sizeof(data));

        if (!ReadFile((HANDLE)(*PipeRead), data, 4096, &data_read, NULL))

            continue;

        CString str(_T("儿子说:"));

        AfxGetApp()->m_pMainWnd->GetDlgItemText(IDC_EDIT_Recv, str);

        str += _T("儿子说:") + (CString)data + _T("\r\n");

        AfxGetApp()->m_pMainWnd->SetDlgItemText(IDC_EDIT_Recv, str);

        Sleep(100);

    }

    return data_read;

}

void CFatherDlg::OnBnClickedButtonSend()

{

    // TODO: 在此添加控件通知处理程序代码/

    CString str;

    GetDlgItemText(IDC_EDIT_Send, str);

    my_SendDataPipe(str);

}

 

子进程核心代码:

void CSonDlg::my_PipeInit()

{

    if (!my_GetParentPipeHandle()) 

        return; //初始化管道

    

    HANDLE hThread = CreateThread(NULL0, Pipe_Listen, &m_hPipeRead, 0NULL); //创建socket的发送线程

    关闭该接收线程句柄,释放引用计数

    CloseHandle(hThread);

}

 

bool CSonDlg::my_GetParentPipeHandle()

{

    m_hPipeWrite  = GetStdHandle(STD_OUTPUT_HANDLE);

    m_hPipeRead  = GetStdHandle(STD_INPUT_HANDLE   );

    if (INVALID_HANDLE_VALUE == m_hPipeRead || INVALID_HANDLE_VALUE == m_hPipeWrite)

    {

        MessageBox(_T("从父进程获得管道读写句柄失败"));

        CloseHandle(m_hPipeRead);

        CloseHandle(m_hPipeWrite);

        return false;

    }

    return true;

}

 

void CSonDlg::my_SendDataPipe(CString data)

{

    DWORD data_write;

    //写入数据

    if (!WriteFile(m_hPipeWrite, (LPCTSTR)data, data.GetLength() * 2, &data_write, NULL))

    {

        MessageBox(_T("发送信息失败"));

    }

}

DWORD WINAPI  CSonDlg::Pipe_Listen(LPVOID lpParameter)  //接收管道数据线程

{

    HANDLE* PipeRead = (HANDLE*)lpParameter;

    TCHAR data[4096] = { 0 };

    DWORD data_read;

    while (true)

    {

        memset(data, 0sizeof(data));

        if (!ReadFile((HANDLE)(*PipeRead), data, 4096, &data_read, NULL))

            continue;

        CString str(_T("爸爸说:"));

        AfxGetApp()->m_pMainWnd->GetDlgItemText(IDC_EDIT_Recv, str);

        str += _T("爸爸说:") + (CString)data + _T("\r\n");

        AfxGetApp()->m_pMainWnd->SetDlgItemText(IDC_EDIT_Recv, str);

        //Sleep(200);

    }

    return data_read;

}

 

 

void CSonDlg::OnBnClickedButtonSend()

{

    // TODO: 在此添加控件通知处理程序代码 

    CString str;

    GetDlgItemText(IDC_EDIT_Send, str);

    my_SendDataPipe(str);

}

 

内核的两个匿名管道示意图如下:

 

      si.hStdInput = m_hPipeRead1;       //子进程的标准输入

    si.hStdOutput = m_hPipeWrite2;   //子进程的标准输出

 

 

运行结果如下:

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC是微软基于C++的一个应用程序框架,它可以帮助开发人员快速创建Windows应用程序。进程间通信(IPC)是不同进程之间进行数据交换和通信的一种方法。管道是一种常见的IPC机制,它允许两个进程之间进行双向通信。 在MFC中,使用管道进行进程间通信可以分为两个步骤:创建管道和使用管道进行通信。 首先,需要创建一个管道。可以使用CreatePipe函数来创建匿名管道,它接受两个参数,第一个参数是用于接收管道句柄的指针,第二个参数是用于发送管道句柄的指针。成功创建管道后,你将获得两个句柄,一个用于读取数据,一个用于写入数据。 然后,可以使用ReadFile和WriteFile函数来读取和写入管道中的数据。这些函数可以传入一个管道句柄,一个缓冲区来存储数据以及数据的长度。通过这些函数,可以在两个进程之间传递数据。 如果需要实现双向通信,可以在每个进程中使用一个管道来进行读取和写入操作。这样,两个进程就可以通过各自的管道进行双向通信了。例如,进程A使用管道A向进程B发送数据,进程B使用管道B向进程A发送数据。 总结起来,MFC可以使用管道进行进程间通信,通过创建管道和使用ReadFile和WriteFile函数来实现数据的读取和写入。如果需要双向通信,则可以在两个进程中分别创建管道来进行双向数据传输。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值