使用命名管道的C ++ / C#通信

处理需要在C#和C ++应用程序之间进行命名管道通信的服务。 最终,C#将作为会话0中的服务运行,而C ++将作为用户会话中的GUI运行。 我为C#应用程序创建了命名管道服务器类,并为C ++应用程序创建了命名管道客户端类以及运行测试所需的GUI。

从我所能看到的,我能够正确连接。 在连接时,C ++客户端通信线程写入一个初始的“连接”消息,然后等待“已连接”响应。 当调试到两个应用程序的运行时,我都通过两个命名的管道连接。 客户端发送它的连接消息,返回值为true。 然后客户端等待阅读回应。 同时服务器直接等待阅读最初的消息。 这两个读块都不会返回。

据我所知,连接是好的。 C#和C ++应用程序都将其管道连接定义为READ / WRITE(在C#中为inOut),并且都定义了使用消息模式的连接。 我能看到的唯一真正的区别是,我已经将C#端的连接定义为允许1个服务器实例,而在C ++端我还没有找到如何完成这个定义。 我似乎无法找到答案,而且我在网上查找,并没有看到任何人将此视为他们的问题。

将C#客户机和服务器作为单独的应用程序进行连接和完美通信,并将C ++客户机和服务器作为单独的应用程序运行。 但是在连接C#和C ++应用程序时出现了这个问题。

代码如下。 对不起,但尽可能小,而不会失去可能实际上是问题一部分的错综复杂。 我从一个在C#和C ++端拥有服务器和客户端的测试项目中减少了这一点。 这里的任何帮助表示赞赏。 如果有人想要该项目的压缩文件,请告诉我如何才能将其提供给您:

C#代码:

using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;

namespace NamedPipeCSharp
{
    class NamedPipeServer
    {
        /*******************************************
         * Member constants
         *******************************************/
        const int numConnects = 2;
        const int ConnSourceBE = 0;
        const int ConnSourceGUI = 1;

        /*******************************************
         * Public member variables
         *******************************************/
        private static bool m_shouldContinue = true;
        private Thread m_serverThread;

        public static void ServerThread(object data)
        {
            NamedPipeServerStream beServer = new NamedPipeServerStream("MyNamedPipe",
                PipeDirection.InOut, 1, PipeTransmissionMode.Message);
            beServer.WaitForConnection();
            StreamReader reader = new StreamReader(beServer);
            StreamWriter writer = new StreamWriter(beServer);
            String startProtocolMsg = "Connecting";
            String startProtocolRsp = "Connected";
            while (m_shouldContinue)
            {
                // block on read input
                String line = reader.ReadLine();
                if (line == startProtocolMsg)
                {
                    writer.WriteLine(startProtocolRsp);
                    writer.Flush();
                }
                Thread.Sleep(10);
            }
        }

        public void StartCommunication()
        {
            // Start a thread to send IPC communications as Backend and GUI
            m_serverThread = new Thread(NamedPipeServer.ServerThread);
            m_serverThread.IsBackground = true;
            m_serverThread.Start();
        }

        public void StopCommunication()
        {
            m_shouldContinue = false;

            if (m_serverThread != null)
            {
                m_serverThread.Join();
                m_serverThread = null;
            }
        }
    }
}

C ++ NamedPipeClient类头:

#ifndef NAMEDPIPESERVER_H
#define NAMEDPIPESERVER_H

#include <QtWidgets/QMainWindow>
#include <Windows.h>
#include <queue>

class NamedPipeClient
{
public:
    NamedPipeClient();
    ~NamedPipeClient();

    void startCommunication();
    void stopCommunication();
    bool shouldContinue();

    // message functions
    bool hasMessageIn();
    bool hasMessageOut();
    std::string nextMessageIn();
    std::string nextMessageOut();

private:
    // Thread function
    static DWORD WINAPI clientThread(LPVOID param);

    // Thread management
    HANDLE createThread(DWORD WINAPI threadFunc(LPVOID), void* objPtr);

private:
    HANDLE m_clientThreadHandle;
    std::queue<std::string> m_inMessageQueue;
    std::queue<std::string> m_outMessageQueue;
    unsigned long m_serverId;
    bool m_shouldContinue;
};

#endif // NAMEDPIPESERVER_H

C ++ NamedPipeClient类的定义:

#include "NamedPipeClient.h"
#include "NamedPipeStream.h"

NamedPipeClient::NamedPipeClient() :
    m_clientThreadHandle(0),
    m_shouldContinue(true)
{
}

NamedPipeClient::~NamedPipeClient()
{
}

void NamedPipeClient::startCommunication()
{
    // Start a thread to send IPC communications from Backend
    m_clientThreadHandle = createThread(clientThread, this);
    if (m_clientThreadHandle && m_clientThreadHandle != INVALID_HANDLE_VALUE)
    {
        ResumeThread(m_clientThreadHandle);
    }
}

void NamedPipeClient::stopCommunication()
{
    // set this particular named pipe server's should continue to false
    m_shouldContinue = false;

    if (m_clientThreadHandle != INVALID_HANDLE_VALUE)
    {
        WaitForSingleObject(m_clientThreadHandle, INFINITE);
        m_clientThreadHandle = 0;
    }
}

/**********************************
 *  Thread function definitions
 **********************************/

DWORD WINAPI NamedPipeClient::clientThread(LPVOID param)
{
    NamedPipeClientStream* beClient = new NamedPipeClientStream("MyNamedPipe", OPEN_EXISTING);
    if (beClient->validPipe())
    {
        NamedPipeClient* thisPtr = static_cast<NamedPipeClient*>((void*)param);
        // start by sending initial message to get things rolling
        std::string startProtocolMsg = "Connecting";
        std::string startProtocolRsp = "Connected";
        std::string message;
        std::string response;
        char buff[BUFSIZE];
        int iterNum = 0;
        int numTries = 0;

        // initial connection protocol
        message = startProtocolMsg;
        bool ok = beClient->writeToPipe(message);
        // wait for correct response
        response = beClient->readFromPipe();
        if (response != startProtocolRsp)
            return -1;

        while (thisPtr->shouldContinue())
        {
            if (thisPtr->hasMessageIn())
            {
                //send the next communication
                message = thisPtr->nextMessageIn();
                while (!beClient->writeToPipe(message))
                {
                    // try sending this message up to 10 times
                    numTries++;
                    if (numTries == 10)
                    {
                        break;
                    }
                    Sleep(2);
                    continue;
                }
                numTries = 0;

                // then sit and wait for an answer
                response = beClient->readFromPipe();
                if (response.length() == 0)
                {
                    Sleep(1);
                }
            }
            Sleep(10);
        }
        return 0;
    }
    else
        return -1;
}

HANDLE NamedPipeClient::createThread(DWORD WINAPI threadFunc(LPVOID), void* objPtr)
{
    // create a thread suspended and return the handle
    HANDLE hThread = CreateThread(
                NULL, // default security
                0, // default stack size
                (LPTHREAD_START_ROUTINE)threadFunc, // Thread
                (LPVOID) objPtr, // arguments
                CREATE_SUSPENDED, //0, // default creation flags
                NULL);     
    return hThread;
}

bool NamedPipeClient::shouldContinue()
{
    return m_shouldContinue;
}

bool NamedPipeClient::hasMessageIn()
{
    return (m_inMessageQueue.size() > 0);
}

bool NamedPipeClient::hasMessageOut()
{
    return (m_outMessageQueue.size() > 0);
}

std::string NamedPipeClient::nextMessageIn()
{
    std::string msg = m_inMessageQueue.front();
    m_inMessageQueue.pop();
    return msg;
}

std::string NamedPipeClient::nextMessageOut()
{
    std::string msg = m_outMessageQueue.front();
    m_outMessageQueue.pop();
    return msg;
}

C ++ NamedPipeStream类头:

#ifndef NAMEDPIPESTREAM_H
#define NAMEDPIPESTREAM_H

#include <Windows.h>
#include <string>

#define BUFSIZE 512

class NamedPipeStream
{
public:
    NamedPipeStream(std::string pipeName, int createMode);
    ~NamedPipeStream();

    virtual bool writeToPipe(std::string message);
    virtual std::string readFromPipe();
    virtual bool closePipe() = 0;
    bool validPipe();

protected:
    void createPipe(std::string pipeName);
    virtual HANDLE openPipe(wchar_t* pipeName) = 0;

protected:
    std::string m_pipeName;
    HANDLE m_pipeHandle; 
    int m_createMode;
    bool m_closePipe;
    bool m_isValid;
};

class NamedPipeClientStream : public NamedPipeStream
{
public:
    NamedPipeClientStream(std::string pipeName, int createMode = CREATE_NEW);
    ~NamedPipeClientStream();

    bool closePipe();

private:
    HANDLE openPipe(wchar_t* pipeName);
};

C ++ NamedPipeStream类的定义:

#include "NamedPipeStream.h"
#include <stdlib.h>

/**********************************************
 *
 *  NamedPipeStream class
 *
 *  Definition: Abstract base class for named pipes
 *
 **********************************************/

NamedPipeStream::NamedPipeStream(std::string pipeName, int createMode) :
    m_pipeName(pipeName),
    m_createMode(createMode),
    m_closePipe(false),
    m_isValid(false)
{
}

NamedPipeStream::~NamedPipeStream()
{
}

bool NamedPipeStream::writeToPipe(std::string message)
{
    DWORD numToWrite, numWritten; 
    BOOL fSuccess = FALSE; 
    wchar_t* lpvMessage;

    // Send a message to the pipe server. 
    std::wstring wsMessage(message.begin(), message.end());
    lpvMessage = const_cast<wchar_t*>(wsMessage.c_str());

    numToWrite = (lstrlen(lpvMessage)+1)*sizeof(TCHAR);

    fSuccess = WriteFile( 
        m_pipeHandle,     // pipe handle 
        lpvMessage,       // message 
        numToWrite,       // message length 
        &numWritten,      // bytes written 
        NULL);            // not overlapped 

    if (!fSuccess) 
    {
        return false;
    }

    return true;
}

std::string NamedPipeStream::readFromPipe()
{
    DWORD cbRead;
    TCHAR chBuf[BUFSIZE];
    BOOL fSuccess = FALSE;

    // Read from the pipe. 
    fSuccess = ReadFile( 
        m_pipeHandle,           // pipe handle 
        chBuf,                  // buffer to receive reply 
        BUFSIZE*sizeof(TCHAR),  // size of buffer 
        &cbRead,                // number of bytes read 
        NULL);                  // not overlapped 

    if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
    {
        // return empty string on error
        return std::string(); 
    }

    std::wstring instr(chBuf);
    return std::string(instr.begin(), instr.end());
}

bool NamedPipeStream::validPipe()
{
    return m_isValid;
}

void NamedPipeStream::createPipe(std::string pipeName)
{
    BOOL   fSuccess = FALSE; 
    DWORD  cbRead, cbToWrite, cbWritten, dwMode; 
    char* szPipenameFormat = "\.pipe";
    std::string pipeNameStr;
    size_t formatLen = 0;
    wchar_t* lpszPipenameFormat = NULL;
    char* szPipename = NULL;

    // convert std::string name to wide char pointer and append to format string
    pipeNameStr = szPipenameFormat;
    pipeNameStr.append(pipeName);
    lpszPipenameFormat = new wchar_t[pipeNameStr.length()+1];
    szPipename = const_cast<char*>(pipeNameStr.c_str());
    mbstowcs_s(&formatLen, lpszPipenameFormat, pipeNameStr.length()+1, 
        szPipename, pipeNameStr.length());
    lpszPipenameFormat[pipeNameStr.length()+1] = NULL;

    // Try to open a named pipe; wait for it, if necessary. 
    // loop until get a valid named pipe
    while (1) 
    { 
        m_pipeHandle = openPipe(lpszPipenameFormat);

        // Break if the pipe handle is valid. 
        if (m_pipeHandle != INVALID_HANDLE_VALUE) 
        {
            DWORD err = GetLastError();
            break; 
        }

        // Exit if an error other than ERROR_PIPE_BUSY occurs. 
        if (GetLastError() != ERROR_PIPE_BUSY) 
        {
            DWORD err = GetLastError();
            m_isValid = false;
            return;
         }

        // All pipe instances are busy, so wait for 20 seconds. 
        if (!WaitNamedPipe(lpszPipenameFormat, 20000)) 
        { 
            m_isValid = false;
            return;
        } 
    } 

    // The pipe connected; change to message-read mode. 
    dwMode = PIPE_READMODE_MESSAGE; 
    fSuccess = SetNamedPipeHandleState( 
        m_pipeHandle,    // pipe handle 
        &dwMode,  // new pipe mode 
        NULL,     // don't set maximum bytes 
        NULL);    // don't set maximum time 
    if (!fSuccess) 
    {
        m_isValid = false;
        return;
    }

    m_isValid = true;
}

/****************************************************
 *
 *  NamedPipeClientStream class
 *
 *  Definition: Class for creating server named pipe
 *              to open client connection
 *
 ****************************************************/

NamedPipeClientStream::NamedPipeClientStream(std::string pipeName, int createMode)
    : NamedPipeStream(pipeName, createMode)
{
    createPipe(pipeName);
}

NamedPipeClientStream::~NamedPipeClientStream()
{
}

HANDLE NamedPipeClientStream::openPipe(wchar_t* lpPipeName)
{
    HANDLE hPipe = CreateFile( 
        lpPipeName,     // pipe name 
        GENERIC_READ |  // read and write access 
        GENERIC_WRITE, 
        0,              // no sharing 
        NULL,           // default security attributes
        m_createMode,   // specifies whether create new or open existing
        0,              // default attributes 
        NULL);          // no template file 
    return hPipe;
}

bool NamedPipeClientStream::closePipe()
{
    m_closePipe = true;
    return (CloseHandle(m_pipeHandle) == TRUE) ? true : false;
}
链接地址: http://www.djcxy.com/p/48291.html

上一篇: C++ / C# Communication using Named Pipes

下一篇: USB Communication, Read Message with Multithreading