Нужны предложения по правильной реализации канала управления (IPC) между VC++ и C#
Я работаю над проектом, в котором взаимодействую между компонентами VC++ (сервер) и клиентом C#.
Компонент C# запускается VC++, и дальнейшие взаимодействия происходят между этими компонентами по каналам управления.
Канал управления создается на VC++ следующим образом:
StartNamedPipeServer(const wchar_t* wszParametersXML) { m_hServerPipe = ::CreateNamedPipe(m_wszServerPipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, MAX_PATH, MAX_PATH, 0, NULL); if(m_hServerPipe!=INVALID_HANDLE_VALUE) { ::ConnectNamedPipe(m_hServerPipe, NULL); } DWORD dwWrite=0; ::WriteFile(m_hServerPipe, szFilePath, strlen(szFilePath), &dwWrite, NULL); // Writes some data to control pipe (usually a file path) return 0; }
Контрольная труба создана и подключена нормально. В конце C# данные принимаются без каких-либо проблем, и C# (клиент) записывает обратно в тот же канал сообщения "wait" и "proceed", как показано ниже.
while (true) { using (NamedPipeClientStream ClientPipeStream = new NamedPipeClientStream(".", NamedClientPipe, PipeDirection.InOut)) { while (true) { try { //The connect function will connect to the pipe if available ClientPipeStream.Connect(1000); break; } catch { // Pipe is not connected - re attempt continue; } } //Read server reply StreamReader ClientStream = new StreamReader(ClientPipeStream); char[] param = new char[260]; while (ClientStream.Peek() >= 0) { ClientStream.Read(param, 0, param.Length); } using (StreamWriter ServerStreamWriter = new StreamWriter(ClientPipeStream)) { try { ServerStreamWriter.AutoFlush = true; ServerStreamWriter.WriteLine("wait"); StartProcessing(modelFolderPath, mailslotName, ControlPipeName); // ControlpipeName will be available and it is same as connected one // Task processing Implementation takes some 1 - 5 mins ServerStreamWriter.WriteLine("proceed"); System.Threading.Thread.Sleep(1000); } catch (Exception ex) { ServerStreamWriter.WriteLine("proceed"); System.Threading.Thread.Sleep(1000); retvalue = FAILURE; //program failed } } } }
VC++ считывает сообщения для дальнейшей обработки, как показано ниже.
ReadNamedPipeServer() { char szClientUpdate[100]; BOOL bSuccess=FALSE; for (;;) { DWORD dwBytesAvail = 0; if(!::PeekNamedPipe(m_hServerPipe, NULL, 0, NULL, &dwBytesAvail, NULL) || dwBytesAvail > 0) { //SendText(L"Read some data from pipe"); DWORD dwRead=0; bSuccess = ::ReadFile(m_hServerPipe, szClientUpdate, sizeof(szClientUpdate), &dwRead, NULL); if (bSuccess) { if(strncmp(szClientUpdate, "wait", 4) == 0) { return 1; } if(strncmp(szClientUpdate, "proceed", 7) == 0) { return 0; } } }
Нужны предложения экспертов и изменения дизайна, если здесь что-то потребуется.
Что я уже пробовал:
Сервер ReadNamedPipe работает нормально, и сообщения "wait" и "proceed" читаются нормально. но иногда, когда пишется "продолжить", канал не считывается методом VC++ ReadNamedPipeServer (), и программа переходит в бесконечный цикл и зависает поток приложений.(Это происходит в некоторых конкретных машинах, таких как Win 10 64Bit и иногда в Win7 64bit машинах).
Richard MacCutchan
Вы не должны создавать бесконечный цикл без какого-либо способа вырваться, когда он не читает действительное сообщение. Кроме того, ваш if
утверждение выглядит неверно. Если PeekNamedPipe
возвращает ноль, а затем вы пытаетесь прочитать из трубы.
Jagssnaik
Привет Ричард,
Спасибо за помощь. Я исправил свою петлю if.
Что касается бесконечного цикла-я пытаюсь вернуться в зависимости от сообщений, отправленных клиентом, но иногда клиент записывает в канал, а сервер не может читать из-за сломанной трубы или какой-то другой ошибки.
Я новичок в IPC, поэтому не могли бы вы подсказать, каким образом я могу разорвать петлю?
if (! bSuccess && (:: GetLastError() == ERROR_BROKEN_PIPE))
{
возвращает 0;
}
Попытка сделать это будет полезна ? Не могли бы вы предложить какую-нибудь лучшую альтернативу?
Richard MacCutchan
не совсем. Проблема заключается в том, как управлять системой, в которой данные поступают случайным образом. Вам нужен какой-то способ опросить удаленное устройство или получить сигнал, когда поступят какие-то данные. В любом случае вам нужно проверить, что пришло, и обработать это соответствующим образом. Если данных нет, то вам нужно использовать какой-то механизм, чтобы дождаться, пока они появятся. Информация, возвращаемая функцией peek, должна помочь вам принять эти решения. Изучите документацию, чтобы увидеть наилучший способ ее обработки.
Jagssnaik
Привет, Ричард, Спасибо за ваши предложения. Я попробую.
OverlappedIO-это то,что вы предлагаете?