Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Работа с Named Pipe, Повторное использование открытого канала 
:(
    Опции темы
Usper
Дата 19.10.2009, 08:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15



Для разрабатываемого приложения требуется межпроцессное взаимодействие. Выбор пал на именованые каналы. Всё вроде бы работает, но только до тех пор, пока клиент не закроет канал со своей стороны. После этого клиент повторно присоединиться к серверу не может, функция CreateFile() возвращает INVALID_HANDLE_VALUE. Что должен делать сервер, после того как канал будет закрыт со стороны клиента? Создать канал заново? Как серверу определить, что клиент уже закрыл канал?

Код


HANDLE hPipe;

void __fastcall TMonPipe::Execute()
{
    char pBuf[BufSize];
    unsigned long cbRead;
    hPipe = CreateNamedPipe("\\\\.\\pipe\\$MonitorPipe$",PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES, BufSize, BufSize, 1000, NULL);
    if(hPipe==INVALID_HANDLE_VALUE)
    {
        ErrorMessage="Не удалось открыть канал взаимодействия приложений.";
        Synchronize(CallShowMessageFunction);
        return;
    }
    while(!Terminated)
    {
        UpdCapt="Нет коннекта";
        Synchronize(UpdateCaption);
        if(ConnectNamedPipe(hPipe, NULL))
        {
            UpdCapt="Есть коннект";
            Synchronize(UpdateCaption);
            while(!Terminated)
            {
                if(ReadFile(hPipe, pBuf, BufSize, &cbRead, NULL))
                {
                    if(AnsiString(pBuf)=="Test") {SendMessage("Test - Ok"); Synchronize(UpdateCaption);}
                    Synchronize(UpdateCaption);

                }
                else
                    /*if(GetLastError()==ERROR_PIPE_CONNECTED)*/ break;
            }
         }
    }
}



--------------------
На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.
PM MAIL   Вверх
xvr
Дата 19.10.2009, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Сервер должен создать (позвать CreateNamedPipe) столько именнованных каналов, сколько он хочет обслужить клиентов зараз (т.е. в вашем случае 1000 раз)
Каждый вызов ConnectNamedPipe подключает ОДНОГО клиента, для подключения следующего клиента сервер опять должен позвать ConnectNamedPipe

Цитата

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

PM MAIL   Вверх
Usper
Дата 19.10.2009, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15



Да нет, мне не нужно одновременно работать с тысячью клиентов (с чего вы взяли?). Достаточно и одного. Но в любом случае, что тогда означет параметр nMaxInstances в функции CreateNamedPipe?
Цитата

nMaxInstances

Specifies the maximum number of instances that can be created for this pipe. The same number must be specified for all instances. Acceptable values are in the range 1 through PIPE_UNLIMITED_INSTANCES. If this parameter is PIPE_UNLIMITED_INSTANCES, the number of pipe instances that can be created is limited only by the availability of system resources. 




--------------------
На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.
PM MAIL   Вверх
xvr
Дата 19.10.2009, 15:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Usper @ 19.10.2009,  15:39)
Да нет, мне не нужно одновременно работать с тысячью клиентов (с чего вы взяли?). Достаточно и одного. Но в любом случае, что тогда означет параметр nMaxInstances в функции CreateNamedPipe?

Вот это собственно и значит - количество инстансов именновоного пайпа, которые вы собираетесь создать. (Отсюда я и взял число 1000 Пардон, не туда посмотрел - у вас вообще PIPE_UNLIMITED_INSTANCES)
Но этот параметр никоим образом не заставляет Винду создать все эти инстантсы  smile Результат ОДНОГО вызова CreateNamedPipe может одновременно обработать не более ОДНОГО клиента. Если вам нужно больше - создавайте еще (сами)

После отключения клиента, сервер должен позвать DisconnectNamedPipe на хэндлере, где был клиент, а потом может снова звать ConnectNamedPipe


Это сообщение отредактировал(а) xvr - 19.10.2009, 16:04
PM MAIL   Вверх
Usper
Дата 20.10.2009, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15



Спасибо за советы, всё заработало. Однако аппетит приходит во время еды  smile. Сейчас столкнулся с тем, что клиент во время чтения из канала виснет намертво, если сервер ничего не пишет в канал. То есть функция ReadFile() бесконечно ждёт информацию от сервера. Как этого избежать? Можно сделать так, чтобы функция по истечении определённого времени возвращала какой-нибудь результат (Как например это сделано при работе с COM портами)?


--------------------
На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.
PM MAIL   Вверх
xvr
Дата 20.10.2009, 11:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Usper @ 20.10.2009,  09:19)
Сейчас столкнулся с тем, что клиент во время чтения из канала виснет намертво, если сервер ничего не пишет в канал. То есть функция ReadFile() бесконечно ждёт информацию от сервера. Как этого избежать? 

Использовать Overlapped IO или неблокирующий режим открытия Named Pipe'а


PM MAIL   Вверх
Usper
Дата 10.11.2009, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15



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


--------------------
На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.
PM MAIL   Вверх
xvr
Дата 10.11.2009, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Usper @ 10.11.2009,  14:11)
А можно поподробнее про эти режимы? 

Совершенно обычные режимы Overlapped IO. Любая функция в Overlapped режиме только стартует операцию и немедленно возвращается с ошибкой ERROR_IO_PENDING. Дальше программа может заниматься чем хочет, а когда операция наконец выполнится, то система взведет Event (который подавался как параметр в оригинальную функцию)
Неблокирующий режим просто сразу возвращается с ошибкой, т.е. программа должна периодически пробовать снова и снова

Цитата

Сервер ведь может и не ответить вообще, клиент при этом не должен зависать. В этих условиях эти режимы подходят?
Подходят, но сами по себе эти режимы не обеспечат независание и бесперебойную работу - нужно грамотно сделать дезайн проекта. В этом режимы помогут  smile 
PM MAIL   Вверх
Usper
Дата 11.11.2009, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 325
Регистрация: 13.4.2007

Репутация: 15
Всего: 15



А в клиенте надо указать какие-то параметры, указывающие на то, что необходимо работать в неблокирующем режиме? У меня почему-то функция ReadFile всё ещё бесконечно ждёт ответа сервера.

Сервер:
Код
...
void __fastcall TMonPipe::Execute()
{
    char pBuf[BufSize];
    unsigned long cbRead;
    hPipe = CreateNamedPipe("\\\\.\\pipe\\$MonitorPipe$",PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
        1, BufSize, BufSize, 1000, NULL);
        if(hPipe==INVALID_HANDLE_VALUE)
        {
            ErrorMessage="Не удалось открыть канал взаимодействия приложений.";
            Synchronize(CallShowMessageFunction);
            return;
        }
    while(!Terminated)
    {
        UpdCapt="Нет коннекта";
        Synchronize(UpdateCaption);
        //if(ConnectNamedPipe(hPipe, NULL))
        ConnectNamedPipe(hPipe, NULL);
        if(GetLastError()==ERROR_PIPE_CONNECTED)
        {
            UpdCapt="Есть коннект";
            Synchronize(UpdateCaption);
            while(!Terminated)
            {
                if(ReadFile(hPipe, pBuf, BufSize, &cbRead, NULL))
                {
                    if(AnsiString(pBuf)=="Test") SendMessage("Test - Ok");

                }
                else
                    if(GetLastError()!=ERROR_NO_DATA)
                    {
                        DisconnectNamedPipe(hPipe);
                        break;
                    }
                Sleep(50);    
            }
         }
         Sleep(50);
         //CloseHandle(hPipe);
    }
}

void __fastcall TMonPipe::SendMessage(AnsiString S)
{
    unsigned long cbWritten;
    WriteFile(hPipe, S.c_str(), S.Length()+1,&cbWritten, NULL);
}
...


Клиент:
Код
...
    hPipe = CreateFile(
    "\\\\192.168.0.4\\pipe\\$MonitorPipe$", GENERIC_READ | GENERIC_WRITE,
    0, NULL, OPEN_EXISTING, 0, NULL);
    if(hPipe==INVALID_HANDLE_VALUE)
    {
        Application->MessageBoxA("Ошибка открытия канала","Ошибка",MB_ICONERROR);
        return;
    }
...
    char szBuf[512];
    unsigned long cbRead;
    WriteFile(hPipe, Edit1->Text.c_str(), Edit1->Text.Length()+1,
      &cbWritten, NULL);
    int counter;
    counter=0;
    while(1)
    {
    counter++;
    if(ReadFile(hPipe, szBuf, 128, &cbRead, NULL))
    {
        Memo1->Lines->Add("Принято:"+AnsiString(szBuf));
        break;
    }
    if(szBuf==0 && counter<20) {Sleep(50); continue;}
    else {Memo1->Lines->Add("Выход по таймауту");break;}
    }
...




--------------------
На посохе волшебном нехилый набалдашник, большой такой, огромный, нехилый набалдашник.
PM MAIL   Вверх
xvr
Дата 11.11.2009, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Usper @ 11.11.2009,  13:46)
А в клиенте надо указать какие-то параметры, указывающие на то, что необходимо работать в неблокирующем режиме?

Надо. См. функцию SetNamedPipeHandleState

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0593 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.