Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2004.12.26;
Скачать: [xml.tar.bz2];

Вниз

Клиент - сервер проблема синхронизации   Найти похожие ветки 

 
QuestionX ©   (2004-10-09 15:26) [0]

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


 
Verg ©   (2004-10-09 16:22) [1]


>  когда клиент и сервер одновременно посылают запросы друг
> другу и оба переключаются в режим обработки этих запросов


И что? в чем проблема?


> Перед началом своей работы, клиент устанавливает соединение
> с сервером и при окончании разрывает его.


При окончании... при окончании чего?

Похоже, нехватает форума www.logicmaster.ru


 
QuestionX ©   (2004-10-09 18:04) [2]


> При окончании... при окончании чего?

Перед началом своей работы, клиент устанавливает соединение с сервером и при окончании [своей работы] разрывает его.

> И что? в чем проблема?

Цикл работы сервера:
1: Ожидать получения команды от пользователя или системного события
  Если получение команды то 2 иначе 3

2: Считать команду
  <Ожидать получения command specific данных
  Считать данные
  Ответить клиенту>
  Перейти к 1

3: Послать команду клиенту
  Ожидать получения данных ответа
  Считать данные
  Перейти к 1


Цикл работы клиента:
1: Ожидать получения команды от сервера или запроса от пользователя
  Если получение команды то 2 иначе 3

2: Считать команду
  <Ожидать получения command specific данных
  Считать данные
  Ответить серверу>
  Перейти к 1

3: Послать команду серверу
  Ожидать получения данных ответа
  Считать данные
  Перейти к 1


Так вот, если предположить одновременное возникновение запроса пользователя на клиенте и системного события на сервере, то
1: сервер переключится в режим Ожидать получения command specific данных (N байт) и получит вместо них команду клиента (4 байта)

2: клиент будет Ожидать получения данных ответа (N байт) а получит вместо них команду от сервера (4 байта)

Так они и остануться висеть в ожидании несбыточного, пока тайм-аут не разлучит их навеки.
Вполне возможно, что мне действительно нехватает www.logicmaster.ru но пока я не вижу как иначе решить проблему обмена по одному каналу, не создавая еще одного соединения.


 
Verg ©   (2004-10-09 18:38) [3]

Так все это делается на уровне логики протокола информационного обмена. Каждая сторона ожидает не "то ответа, то запроса", а "ответа или запроса", т.е. готова либо принять ответ, либо запрос в любой момент, в который она вообще чего-либо готова принимать от собеседника. Порции информации должны быть оформлены в одинаково понятном для обеих сторон виде. Например пакетов. Пакет сотоит из заголовка фиксированной длины и тела произвольной длины. Однако длина тела всегда указывается в заголовке пакета. В заголовке так же указывается служебная информация. Например, что это за пакет - запрос или ответ. Если ответ, то указывается на каой запрос. Идентификация ответов идет по уникальному значению в заголовке запроса. По ИД-у. Пример ида - просто cardinal который запрашивающий каждый раз увеличивает на единицу и помещает в поле заголовка запроса. Отвечающий на конкретно этот вопрос помещает ИД того запроса в заголовок паета с ответом на этот запрос....

И т.д. и т.п. и множество существует способов организации взаимодействия....


 
QuestionX ©   (2004-10-09 19:10) [4]


> Каждая сторона ожидает не "то ответа, то запроса", а "ответа
> или запроса", т.е. готова либо принять ответ, либо запрос
> в любой момент

Это то, что я долго и безуспешно пытаюсь сделать. Не могли бы подсказать алгоритм реализации подобного поведения сервера или хотя бы ссылочку где об этом можно почитать.


 
QuestionX ©   (2004-10-12 00:34) [5]

Как ни крути, не могу понять одной вещи. Пусть сервер и клиент могут обмениваться сообщениями, для простоты пусть

THeader = packed record
 Command: Integer;
 BodySize: Integer;
end;
TEvent = (evHeaderRead, evNotify);

Тогда на сервере для каждого подключившегося клиента работает следующий код:

var
 Header: THeader;
 Event: TEvent;
...

while Connected do
 Event := ReadBuffer(Header, sizeof(Buffer)); // Отсюда возврат в 2-х случаях - прочитан присланный клиентом заголовок или сработал объект синхронизации, уведомляющий о системном событии
 case Event of
 evHeaderRead: // Считали заголовок пакета
 begin
   ReadBuffer(Buffer, Header.Size); // Считываем тело пакета
   ... // Обработка
   Header.Command := ...
   Header.Size := ...
   SendBuffer(Header, sizeof(Header)); // Посылаем заголовок ответного пакета
   SendBuffer(Buffer, BufSize); // Посылаем тело пакета
 end;
 evNotify: // Произошло некоторое событие
 begin
   ... // Обработка
   Header.Command := ...
   Header.Size := ...
(*)    SendBuffer(Header, sizeof(Header)); // Посылаем заголовок ответа
   SendBuffer(Buffer, BufSize); // Посылаем тело ответ
   ReadBuffer(Header, sizeof(Buffer)); // Считываем заголовок ответа
   ReadBuffer(Buffer, Header.Size); // Считываем тело ответа
 end;
 end;
end;


На клиенте цикл полностью аналогичен.

И возникает ситуация о которой я говорил выше - коллизия, когда системые события возникают и на сервере и на клиенте и строка (*) срабатывает на обеих сторонах.
Как этого избежать ? Как реализовать "Каждая сторона ожидает не "то ответа, то запроса", а "ответа или запроса", т.е. готова либо принять ответ, либо запрос в любой момент"  подскажите алгоритм, пожалуйста или ссылку на то где это подробно описано.

С уважением.


 
Verg ©   (2004-10-12 06:23) [6]

Если рассуждать в твоих же терминах, то, например:
TCommand = (cmdREQUEST, cmdRESMONSE);

THeader = packed record
Command: Integer; // TCommand
Id     : Cardinal;
BodySize: Integer;
end;
TEvent = (evHeaderRead, evNotify);

var
 CurrentXID : cardinal = 1;
 WaitingRespXid : cardinal = 0;

begin
   while Connected do
   begin
    Event := ReadBuffer(Header, sizeof(Buffer)); // Отсюда возврат в 2-х случаях - прочитан присланный клиентом заголовок или сработал объект синхронизации, уведомляющий о системном событии
    case Event of
      evHeaderRead: // Считали заголовок пакета
      begin
        ReadBuffer(Buffer, Header.Size); // Считываем тело пакета
        case TCommand(Header.Command) of
          cmdREQUEST : begin
                     ... // Обработка
                     Header.Command := ...
                     Header.Size := ...
                     // Заметь - мы оставили поле ID в ответе нетронутым
                     // т.е. ID ответа равен ID-у запроса
                     SendBuffer(Header, sizeof(Header)); // Посылаем заголовок ответного пакета
                     SendBuffer(Buffer, BufSize); // Посылаем тело пакета
          end;
          cmdRESPONSE: begin
            // Принят
             if( WaitingRespXID = Header.Id ) then
             // или определяем нет ли в очереди наших запросов этого Id-а
             begin
             // Принят ответ на недавно отправленный запрос
               WaitingRespXID := 0;
               // Обработка принятого ответа.............
             end;
          end;
        end;
      end;
      evNotify: // Произошло некоторое событие
      begin
        if WaitingRespXID <> 0 then
        begin
          // Мы еще не получили ответа на предыдущий свой запрос
          // поэтому можно либо игнорировать системыное событие
          // либо организовать очередь (напр., Tlist) из своих запросов
          // Тогда WaitingRespXID - это не просто переменная, а некий объект
          // - очередь запросов, которые уже отправлены, но ответы на них
          // не получены
        end;
        ... // Обработка
        repeat
          Inc(CurrentXID);
        until CurrentXID <> 0;
        Header.Command := ord(cmdREQUEST);
        Header.Id      := CurrentXID;
        WaitingRespXID := Header.Id; // либо вносим этот запрос в очередь
                                     // ожидающих ответ
        Header.Size := ...
        SendBuffer(Header, sizeof(Header)); // Посылаем заголовок ответа
        SendBuffer(Buffer, BufSize); // Посылаем тело ответ
      end;
    end;
end;
end;


 
QuestionX ©   (2004-10-12 16:39) [7]


> Verg ©   (12.10.04 06:23) [6]

Спасибо !


 
Verg ©   (2004-10-12 22:21) [8]

Надеюсь, ты понимаешь, что это не код, а лишь принцип, т.е. схема...



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2004.12.26;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.041 c
1-1102706736
kirilllius
2004-12-10 22:25
2004.12.26
Привязка ПО к CD


14-1101230112
alex145
2004-11-23 20:15
2004.12.26
Visual Studio


14-1102307446
Урфин Джюс
2004-12-06 07:30
2004.12.26
Do not localize


14-1102590673
Dmitriy O.
2004-12-09 14:11
2004.12.26
Как оботи требование вставить CD диск для запуска ?


14-1102253374
NailMan
2004-12-05 16:29
2004.12.26
Хорошие ресторанчики для проведения мероприятий





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский