C++ 进程间通信(管道)

进程间通信(封装级别)、可拿入项目中直接使用!!!!!

**

PipeCS.h文件

**

#pragma once
#include <Windows.h>
#include <string>
#include <thread>
#include <iostream>
#include <atomic>
#include <iostream>

class CPipeBase
{
public:
    CPipeBase() = default;
    virtual ~CPipeBase() = default;

    typedef std::function<void(const std::string &szMsg)> TMessageHandler;

protected:
    bool ReadPipe(HANDLE hNamedPipe, std::string &szMsg);
    bool WritePipe(HANDLE hNamedPipe, const std::string &szMsg);
};

class CPipeServer : public CPipeBase
{
public:
    CPipeServer(const std::string &szPipeName, TMessageHandler fnMsgHandler);
    CPipeServer(const CPipeServer &Other) = delete;
    CPipeServer(CPipeServer &&Other) = delete;
    ~CPipeServer();

    CPipeServer& operator=(const CPipeServer &Other) = delete;
    CPipeServer& operator=(CPipeServer &&Other) = delete;

    void Run();
    void Stop();
    bool SendMsg(const std::string &szMsg);

private:
    bool ConnectClient();
    void DisconnectClient();
    bool CreatePipeInstance(const std::string &szPipeName, HANDLE &hPipeInstance);
    void Close();

private:
    std::string m_szPipeName;
    TMessageHandler m_fnMsgHandler;
    HANDLE m_hNamedPipeR;
    HANDLE m_hNamedPipeW;
};

class CPipeClient : public CPipeBase
{
public:
    CPipeClient(const std::string &szPipeName, TMessageHandler fnMsgHandler);
    CPipeClient(const CPipeClient &Other) = delete;
    CPipeClient(CPipeClient &&Other) = delete;
    ~CPipeClient();

    CPipeClient& operator=(const CPipeClient &Other) = delete;
    CPipeClient& operator=(CPipeClient &&Other) = delete;

    bool IsConnected() const;
    bool Connect(unsigned int nTimeoutSeconds);
    void Disconnect();

    bool SendMsg(const std::string &szMsg);

protected:
    bool SetMessageMode(HANDLE hNamedPipe);
    void ReadThreadProc();

private:
    std::string m_szPipeName;
    HANDLE m_hNamedPipeW;
    HANDLE m_hNamedPipeR;
    // 消息读取线程
    std::atomic_bool m_bThreadRun = false;
    std::thread m_ReadThread;
    TMessageHandler m_fnMsgHandler;
};

**

PipeCS.cpp文件

**

#include "PipeCS.h"

#define PIPE_BUF_SIZE 1024


bool CPipeBase::WritePipe(HANDLE hNamedPipe, const std::string &szMsg)
{
    if (hNamedPipe == INVALID_HANDLE_VALUE)
    {
        std::cout << "the pipe is invalid." << std::endl;
        return false;
    }

    DWORD dwWritedBytes = 0;
    DWORD dwTotalBytes = szMsg.size();
    DWORD dwSentBytes = 0;
    BOOL bResult = FALSE;

    do
    {
        bResult = ::WriteFile(hNamedPipe, &szMsg[dwSentBytes], dwTotalBytes - dwSentBytes, &dwWritedBytes, NULL);
        if (!bResult || dwWritedBytes == 0)
        {
            std::cout << "write message to pipe error: " << ::GetLastError() << std::endl;
            return false;
        }
        dwSentBytes += dwWritedBytes;
    } while (dwSentBytes < dwTotalBytes);

    return true;
}

bool CPipeBase::ReadPipe(HANDLE hNamedPipe, std::string &szMsg)
{
    szMsg.clear();

    if (hNamedPipe == INVALID_HANDLE_VALUE)
    {
        std::cout << "the pipe is invalid." << std::endl;
        return false;
    }

    bool bResult = false;
    DWORD dwError = ERROR_SUCCESS;
    DWORD dwReadBytes = 0;
    CHAR ReadBuf[PIPE_BUF_SIZE] = { 0 };
    bool bReadMore = false;

    do
    {
        if (::ReadFile(hNamedPipe, ReadBuf, PIPE_BUF_SIZE, &dwReadBytes, NULL))
        {
            // 读成功,跳出
            szMsg.append(ReadBuf, dwReadBytes);
            bResult = true;
            break;
        }

        dwError = ::GetLastError();
        if (dwError == ERROR_MORE_DATA)
        {
            // 没有读完,继续读
            szMsg.append(ReadBuf, dwReadBytes);
            bReadMore = true;
            continue;
        }

        // 其它错误,不再继续读
        bReadMore = false;
        if (dwError == ERROR_BROKEN_PIPE)
        {
            std::cout << "the pipe has disconnected." << std::endl;
        }
        else
        {
            std::cout << "read message from pipe error: " << dwError << std::endl;
        }
    } while (bReadMore);

    return bResult;
}

CPipeServer::CPipeServer(const std::string &szPipeName, TMessageHandler fnMsgHandler) :
    m_szPipeName(szPipeName), m_fnMsgHandler(fnMsgHandler)
{
    m_hNamedPipeR = INVALID_HANDLE_VALUE;
    m_hNamedPipeW = INVALID_HANDLE_VALUE;
}

CPipeServer::~CPipeServer()
{
    Close();
}

void CPipeServer::Run()
{
    std::cout << "pipe server will start." << std::endl;

    std::string szMsg;
    while (ConnectClient())
    {
        while (ReadPipe(m_hNamedPipeR, szMsg))
        {
            std::cout << "recv message success: " << szMsg;
            if (m_fnMsgHandler)
            {
                m_fnMsgHandler(szMsg);
            }
        }

        DisconnectClient();
    }

    Close();
    std::cout << "pipe server will exit." << std::endl;
}

void CPipeServer::Stop()
{
    Close();
}

bool CPipeServer::SendMsg(const std::string &szMsg)
{
    std::cout << "send message: " << szMsg << std::endl;
    bool bSuccess = WritePipe(m_hNamedPipeW, szMsg);
    std::cout << "send message " << (bSuccess ? "success." : "failed.") << std::endl;
    return bSuccess;
}

bool CPipeServer::ConnectClient()
{
    if (m_szPipeName.empty())
    {
        std::cout << "the pipe name is empty." << std::endl;
        return false;
    }

    std::string szFullName("\\\\.\\pipe\\");
    szFullName += m_szPipeName;

    std::cout << "create pipe server: " << m_szPipeName << std::endl;

    if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
    {
        if (!CreatePipeInstance(szFullName, m_hNamedPipeR))
        {
            std::cout << "create pipe server for read failed." << std::endl;
            return false;
        }
        std::cout << "create pipe server for read ok." << std::endl;
    }
    std::cout << "wait for the client to connect read ..." << std::endl;
    if (!::ConnectNamedPipe(m_hNamedPipeR, NULL))
    {
        DWORD dwError = ::GetLastError();
        if (dwError != ERROR_PIPE_CONNECTED)
        {
            std::cout << "wait for the client to connect read error: " << dwError << std::endl;
            return false;
        }
    }

    std::cout << "client is connected." << std::endl;
    if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
    {
        if (!CreatePipeInstance(szFullName, m_hNamedPipeW))
        {
            std::cout << "create pipe server for write failed." << std::endl;
            return false;
        }
        std::cout << "create pipe server for write ok." << std::endl;
    }
    std::cout << "wait for the client to connect write ..." << std::endl;
    if (!::ConnectNamedPipe(m_hNamedPipeW, NULL))
    {
        DWORD dwError = ::GetLastError();
        if (dwError != ERROR_PIPE_CONNECTED)
        {
            std::cout << "wait for the client to connect write error: " << dwError << std::endl;
            return false;
        }
    }

    std::cout << "connect pipe client success." << std::endl;
    return true;
}

void CPipeServer::DisconnectClient()
{
    if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
    {
        ::DisconnectNamedPipe(m_hNamedPipeR);
    }

    if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
    {
        ::DisconnectNamedPipe(m_hNamedPipeW);
    }
}

bool CPipeServer::CreatePipeInstance(const std::string &szPipeName, HANDLE &hPipeInstance)
{
    hPipeInstance = ::CreateNamedPipeA(szPipeName.c_str(),
        PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
        2,
        PIPE_BUF_SIZE,
        PIPE_BUF_SIZE,
        0,
        NULL);
    if (hPipeInstance == INVALID_HANDLE_VALUE)
    {
        std::cout << "create pipe server error: " << ::GetLastError() << std::endl;
        return false;
    }

    return true;
}

void CPipeServer::Close()
{
    if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
    {
        ::CloseHandle(m_hNamedPipeR);
        m_hNamedPipeR = INVALID_HANDLE_VALUE;
    }

    if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
    {
        ::CloseHandle(m_hNamedPipeW);
        m_hNamedPipeW = INVALID_HANDLE_VALUE;
    }
}

//
//

CPipeClient::CPipeClient(const std::string &szPipeName, TMessageHandler fnMsgHandler) :
    m_szPipeName(szPipeName), m_fnMsgHandler(fnMsgHandler)
{
    m_hNamedPipeW = INVALID_HANDLE_VALUE;
    m_hNamedPipeR = INVALID_HANDLE_VALUE;
}

CPipeClient::~CPipeClient()
{
    Disconnect();
}

bool CPipeClient::IsConnected() const
{
    return (m_hNamedPipeW != INVALID_HANDLE_VALUE && m_hNamedPipeR != INVALID_HANDLE_VALUE);
}

bool CPipeClient::Connect(unsigned int nTimeoutSeconds)
{
    if (IsConnected())
    {
        std::cout << "the pipe server is connected." << std::endl;
        return true;
    }

    if (m_szPipeName.empty())
    {
        std::cout << "the pipe server name is empty." << std::endl;
        return false;
    }

    std::string szFullName("\\\\.\\pipe\\");
    szFullName += m_szPipeName;

    std::cout << "connect to pipe server: " << m_szPipeName << " in " << nTimeoutSeconds << "s." << std::endl;

    int64_t nTimeoutMs = nTimeoutSeconds * 1000;
    DWORD dwError = ERROR_SUCCESS;

    do
    {
        // 先连接写管道,再连接读管道
        if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
        {
            m_hNamedPipeW = ::CreateFileA(szFullName.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
            if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
            {
                dwError = ::GetLastError();
            }
            else
            {
                SetMessageMode(m_hNamedPipeW);
            }
        }
        else if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
        {
            m_hNamedPipeR = ::CreateFileA(szFullName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
            if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
            {
                dwError = ::GetLastError();
            }
            else
            {
                SetMessageMode(m_hNamedPipeR);
                std::cout << "connect to pipe server ok." << std::endl;
                m_bThreadRun = true;
                m_ReadThread = std::thread(&CPipeClient::ReadThreadProc, this);
                return true;
            }
        }

        if (nTimeoutSeconds == 0)
        {
            std::cout << "connect to pipe server error: " << dwError << std::endl;
            break;
        }
        if (nTimeoutMs <= 0)
        {
            std::cout << "connect to pipe server timeout: " << dwError << std::endl;
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        nTimeoutMs -= 100;
    } while (true);

    return false;
}

void CPipeClient::Disconnect()
{
    if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
    {
        ::CloseHandle(m_hNamedPipeW);
        m_hNamedPipeW = INVALID_HANDLE_VALUE;
    }

    if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
    {
        ::CloseHandle(m_hNamedPipeR);
        m_hNamedPipeR = INVALID_HANDLE_VALUE;
    }

    m_bThreadRun = false;
    if (m_ReadThread.joinable())
    {
        m_ReadThread.join();
    }
}

bool CPipeClient::SendMsg(const std::string &szMsg)
{
    bool bSuccess = false;
    std::cout << "send message: " << szMsg << std::endl;
    if (m_bThreadRun)
    {
        bSuccess = WritePipe(m_hNamedPipeW, szMsg);
    }
    std::cout << "send message " << (bSuccess ? "success." : "failed.") << std::endl;
    return bSuccess;
}

bool CPipeClient::SetMessageMode(HANDLE hNamedPipe)
{
    // 检查是否为消息模式
    DWORD dwMode = 0;
    if (!::GetNamedPipeHandleStateA(hNamedPipe, &dwMode, NULL, NULL, NULL, NULL, 0))
    {
        std::cout << "query the state of server error: " << ::GetLastError() << std::endl;
        return false;
    }

    if (dwMode != PIPE_READMODE_MESSAGE)
    {
        dwMode = PIPE_READMODE_MESSAGE;
        if (!::SetNamedPipeHandleState(hNamedPipe, &dwMode, NULL, NULL))
        {
            std::cout << "change to message-read mode error: " << ::GetLastError() << std::endl;
            return false;
        }
    }

    std::cout << "change to message-read mode ok." << std::endl;
    return true;
}

void CPipeClient::ReadThreadProc()
{
    std::cout << "read message thread begin." << std::endl;  

    while (m_bThreadRun)
    {
        std::string szMsg;
        if (!ReadPipe(m_hNamedPipeR, szMsg))
        {
            m_bThreadRun = false;
            break;
        }

        if (szMsg.empty())
        {
            continue;
        }

        if (m_fnMsgHandler)
        {
            m_fnMsgHandler(szMsg);
        }
    }

    std::cout << "read message thread end." << std::endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I love LiLi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值