Форум: "Сети";
Текущий архив: 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