2009-12-04 3 views
2

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

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

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

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

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

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(); 

Debugging я могу видеть, что все это хорошо, труба создается и WriteFile записывает мои 23 байт в трубу.

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

ответ

5

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

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

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; 

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

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

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

+0

вы можете рассказать, как реализовать сервер и клиент в одном проекте в VS (C++)? – kushpf

+0

@k_programmer Если вы хотите, чтобы в одном процессе вам нужно было использовать отдельные потоки для сервера и клиента или использовать ReadFileEx & WriteFileEx. Попробуйте реализовать решение, и если у вас есть проблемы, спросите здесь. –

+0

Спасибо за ответ. Я понял, как реализовать сервер и клиент в одном потоке. Кажется странным, но я сделал это как-то, и теперь он работает нормально :) – kushpf

4

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

+0

+1 на ReadFileEx – kenny

0

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

0

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

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

1

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

Смежные вопросы