Трубная связь C ++ - PullRequest
       30

Трубная связь C ++

2 голосов
/ 05 декабря 2009

Я пишу два маленьких приложения на С ++, которые должны общаться. Первым будет сервис, который время от времени должен что-то предупреждать пользователя. Поскольку служба не может создавать окна, я разработал приложение для двух отдельных исполняемых файлов.

Служба будет использовать для связи уведомитель.

Службе нужно только отправлять текстовые сообщения уведомителю, который покажет всплывающее окно в системном трее.

Я пытаюсь использовать именованные каналы, и я думаю, что я почти там, но не совсем там. То, что у меня пока есть:

На стороне уведомителя:

  m_hInPipe = CreateNamedPipe(L"\\\\.\\pipe\\nhsupspipe", PIPE_ACCESS_INBOUND,
                PIPE_WAIT, 1, 1024, 1024, 60, NULL);

То есть я создал канал с именем nhsupspipe, входящий канал.

На стороне сервиса:

if (!WriteFile(m_hOutPipe, "My message to the user?", 23, &escritos, &o))
     std::cout << "ERROR: " << GetLastError();

Отладка Я вижу, что все в порядке, канал создан, и WriteFile записывает мои 23 байта в канал.

Мой вопрос таков: как на стороне уведомителя я смогу прочитать эти байты? Есть ли какое-либо сообщение, отправленное процессу? Должен ли я написать обработчик для трубы? Что-нибудь?

Ответы [ 5 ]

5 голосов
/ 05 декабря 2009

Несколько простых фрагментов от клиента (вашего сервиса) и сервера (уведомителя) [ Примечание: это адаптировано из проекта, который я делал недавно, на который, в свою очередь, оказали сильное "влияние" образцы MSDN из CreateNamedPipe & co ]:

Серверная сторона:

HANDLE hPipe = INVALID_HANDLE_VALUE;
bool bConnected = false;

 hPipe = CreateNamedPipe( L"\\\\.\\pipe\\nhsupspipe",
                          PIPE_ACCESS_DUPLEX,
                          PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                          PIPE_UNLIMITED_INSTANCES,
                          sizeof( Message ),
                          0,
                          0,
                          NULL );

 // failed to create pipe?
 if( hPipe == INVALID_HANDLE_VALUE ){
   return -1;
 }

 // Wait for the client to connect; if it succeeds, 
 // the function returns a nonzero value. If the function
 // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. 
 bConnected = ConnectNamedPipe( hPipe, NULL ) ? true : ( GetLastError() == ERROR_PIPE_CONNECTED );

 if( bConnected ){
  while( true ){ 
   unsigned long ulBytesRead = 0;
   // read client requests from the pipe. 
   bool bReadOk = ReadFile( hPipe,
                            &message,
                            sizeof( message ),
                            &ulBytesRead,
                            NULL );

   // bail if read failed [error or client closed connection]
   if( !bReadOk || ulBytesRead == 0 )
    break;

   // all ok, process the message received

  }
 }
 else{
   // the client could not connect, so close the pipe. 
   CloseHandle( hPipe );
 }

 return 0;

Клиент:

HANDLE hPipe = INVALID_HANDLE_VALUE;

 // create the named pipe handle
 hPipe = CreateFile( L"\\\\.\\pipe\\nhsupspipe",
                     GENERIC_READ | GENERIC_WRITE,
                     0, 
                     NULL, 
                     OPEN_EXISTING,
                     0,
                     NULL );

 // if everything ok set mode to message mode
 if( INVALID_HANDLE_VALUE != hPipe ){
  DWORD dwMode = PIPE_READMODE_MESSAGE;
  // if this fails bail out
  if( !SetNamedPipeHandleState( hPipe, &dwMode, NULL, NULL ) ){
   CloseHandle( hPipe ); 

   return -1;
  }
 }

 unsigned long ulBytesWritten = 0;
 bool bWriteOk = WriteFile( hPipe, 
                            ( LPCVOID )&message, 
                            sizeof( Message ), 
                            &ulBytesWritten, 
                            NULL );

 // check if the writing was ok
 if( !bWriteOk || ulBytesWritten < sizeof( Message ) ){
  return -1;
 }

 // written ok

 return 0;

Сообщение , упомянутое выше, является структурой, которая будет вашим сообщением, которое вы, вероятно, захотите упаковать .

Поскольку в вашем сценарии клиент (служба), вероятно, будет запущен и запущен до того, как сервер (уведомитель) вам понадобится внедрить некую стратегию переподключения на стороне клиента.

И на несколько другой ноте вы должны внимательно рассмотреть то, что сказал г-н Остерман в своем ответе (хотя бы потому, что он Ларри Остерман).

4 голосов
/ 05 декабря 2009

Вам необходимо использовать ReadFile или ReadFileEx (для перекрывающегося ввода-вывода) на стороне уведомителя, как правило, в потоке или цикле сообщений. Также посмотрите документацию для CreateNamedPipe и WaitNamedPipe .

1 голос
/ 05 декабря 2009

В этом случае я бы, вероятно, использовал RPC вместо необработанных именованных каналов. С необработанными именованными каналами вы должны проанализировать данные от клиента, что создает возможность ошибок безопасности. С помощью RPC вы можете позволить RPC анализировать данные, что снижает вероятность появления ошибки.

0 голосов
/ 05 декабря 2009

Если бы я делал это, я бы попросил сторону службы сделать CreateNamedPipe (исходящий), а затем позвонить ConnectNamedPipe, чтобы дождаться подключения уведомителя.

На стороне уведомителя я бы использовал CreateFile с FILE_FLAG_OVERLAPPED. При этом дескриптор канала будет сигнализироваться, когда данные станут доступны для чтения. Ваш уведомитель (предположительно) также будет поддерживать графический интерфейс, поэтому вы, вероятно, захотите, чтобы он вызывал MsgWaitForMultipleObjects в цикле событий. Это будет ожидать обработки сообщений или данных, поступающих в канал для обработки. Это будет работать почти как обычный цикл обработки событий, за исключением того, что его возвращаемое значение немного отличается от GetMessage() - он вернет WAIT_OBJECT_0, если ваш дескриптор будет сигнализирован, или WAIT_OBJECT_0 + 1, если у вас есть сообщение (при условии, что вы сделайте так, чтобы он ожидал на одном дескрипторе - это действительно WAIT_OBJECT_0 + N, где N - это количество дескрипторов, на которых вы его ожидали). По большей части это похоже на обычный цикл PeekMessage или GetMessage - подождите, пока есть, чем заняться, сделайте это, подождите снова.

0 голосов
/ 05 декабря 2009

Не совсем вопрос, но другой вариант - CreateEvent () и файл отображения памяти.

...