使用命名管道的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