Как работать с именованными каналами (сервер C ++, клиент C #) - PullRequest
3 голосов
/ 13 марта 2012

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

На данный момент у меня есть сервер C ++, который ждет, пока клиент подключится и отправит тестовое сообщение.Я примерно следовал этому учебнику , чтобы начать.Соответствующий код ниже:

    #define MESSAGE L"TestMessage"

HANDLE hnamedPipe = INVALID_HANDLE_VALUE;

hnamedPipe = CreateNamedPipe(
    L"\\\\.\\pipe\\testpipe",
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE|
    PIPE_READMODE_MESSAGE|
    PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    1024,
    1024,
    NMPWAIT_USE_DEFAULT_WAIT,
    NULL);

if(hnamedPipe == INVALID_HANDLE_VALUE)
{
        cout << "Failed" << endl;
}

while(true)
{
    cout<< "Waiting for client"<< endl;

    if(!ConnectNamedPipe(hnamedPipe,NULL))
    {
        if(ERROR_PIPE_CONNECTED != GetLastError())
        {
        cout << "FAIL"<< endl;
        }
    }

    cout<<"Connected!"<<endl;

    //Send over the message
    wchar_t chResponse[] = MESSAGE;
    DWORD cbResponse,cbWritten;
    cbResponse = sizeof(chResponse);

    if(!WriteFile(
    hnamedPipe,
    chResponse,
    cbResponse,
    &cbWritten,
    NULL))
    {
        wprintf(L"failiure w/err 0x%08lx\n",GetLastError);
    }
    cout<<"Sent bytes :)" << endl;
}

Код клиента (C #) ниже:

        using (NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut))
        {
            while (true)
            {
                Console.WriteLine("Connecting to server...");
                pipeClient.Connect();

                Console.WriteLine("Connected :)");
                Console.WriteLine(pipeClient.ReadByte());
                pipeClient.Close();
                Console.WriteLine("Closed");
            }

        }

На данный момент у меня есть клиент для успешного подключения к серверу, и он печатаетиз первого байта.Я хочу знать, как сделать 2 вещи:

  1. Прочитать все сообщение - я пытался использовать StreamReader через pipeClient, чтобы прочитать сообщение, но оно зависает на ReadLine () бесконечно.

  2. Постоянно отправлять сообщения - я хочу, чтобы сервер отправлял сообщение за сообщением клиенту, который будет читать их по одному и распечатывать их.Я немного не разбираюсь в IPC, поэтому сначала я попытался заставить клиента отключиться и повторно подключиться к серверу в цикле while (true), пока сервер находится в цикле true, который наверху всегда ждет нового клиентского соединения, прежде чемотправив еще одно сообщение.Моя попытка сделать это в приведенном выше коде.

Любая помощь с этим будет принята с благодарностью.В конечном итоге цель состоит в том, чтобы отправить изображения с сервера на клиент.Затем клиент выводит их на экран в режиме реального времени.Я хотел, чтобы это работало с простыми строковыми сообщениями, прежде чем я попробовал данные изображения.

РЕДАКТИРОВАТЬ:

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

  1. Клиент -> Сервер: индикатор того, что клиенту нужна последняя информация о кадре.(Что-то простое, возможно, целое число без знака со значением 1)
  2. Сервер -> Клиент: Информация о последнем кадре.(Изображение 640x480, сохраненное в байтовом массиве со значениями байтов RGB)
  3. Клиент: отображение кадра на дисплее.

1 Ответ

4 голосов
/ 13 марта 2012

ReadLine зависает, потому что ожидает новой строки, в которую не входит ваше тестовое сообщение.

Если вы хотите, чтобы сервер отправлял сообщения непрерывно, просто поставьте цикл вокруг WriteFile.Вам не нужно подключаться более одного раза.Точно так же в клиенте поместите цикл вокруг ReadLine.

Если каждое сообщение состоит из текста, оканчивающегося символом новой строки, этого должно быть достаточно, но если вы действительно хотите, чтобы клиент канала работал в режиме сообщений, вам нужноcall:

pipeClient.ReadMode = PipeTransmissionMode.Message;

Однако я сомневаюсь, что это будет хорошо взаимодействовать с StreamReader.Вместо этого вы должны читать отдельные сообщения, используя pipeClient.Read.

Обновление

Чтобы ответить на ваш новый вопрос:

На сервере, как только клиентподключился, введите цикл, в котором:

  • Сервер выполняет чтение с клиента.Он будет блокироваться до тех пор, пока клиент не запросит кадр.
  • Сервер отправит кадр.

На клиенте после подключения к серверу введите цикл, в котором:

  • Клиент отправляет сообщение «Пожалуйста, отправьте кадр».
  • Клиент выполняет чтение с сервера, чтобы получить кадр.
  • Клиент отображает кадр.

Я бы не использовал конвейер сообщений.Если кадры фиксированного размера, клиент знает, сколько данных нужно прочитать с сервера.В противном случае, перед кадром должна стоять метка, содержащая его длину.

...