Jagssnaik Ответов: 0

Нужны предложения по правильной реализации канала управления (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-это то,что вы предлагаете?

0 Ответов