Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.05.16;
Скачать: CL | DM;

Вниз

Подтверждение о доставке сообщения.   Найти похожие ветки 

 
NAlexey ©   (2004-03-23 08:34) [0]

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

1) Завел глобальную переменную Delivered: boolean;

на клиенте:

отсылаю:
procedure ...

 function CheckIfDeliver: boolean;
 var
   StartTime: TDateTime;
   DT: Double;
 begin
   Result := False;
   StartTime := Time;
   while not Delivered do
   begin
     DT := Frac(Time - StartTime)*86400;
     if DT > 5 then
       Exit;
     Application.ProcessMessages;
   end;
   Result := True;
 end;

begin
 Delivered := False;
 Socket.SendText("#M", "Сообщение");
 if not CheckIfDeliver then
   ...
end;

procedure TClientData.ClientSocketRead(Sender: TObject;
 Socket: TCustomWinSocket);
var
 Str: string;
begin
 Str := Socket.ReceiveText;
 if Copy(Str , 1, 2) = "#M" then //Сообщение получено.
 begin
   ...
   Socket.SendText("#D", ""); //Ответить что получено.
 end;

 if Copy(Str , 1, 2) = "#D" then //Подтверждение пришло.
   Delivered  := True;


2) На сервере обрабатываю, т.е просто рассылаю полученое всем клиентам.

procedure TxService.ServerSocketClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
var
 Str: string;
 
 procedure Answ;
 var
   I: Integer;
 begin
   with ServerSocket.Socket do
     for I := 0 to ActiveConnections - 1 do
       Socket.SendText(Str);
 end;
 
begin
 Answ(Socket.ReceiveText);
end;


Данный подход почемуто не работает, подозреваю что гдето происходит рассинхронизация. Как вообще реализуются такие вещи?


 
Piople ©   (2004-03-23 08:37) [1]

Клиент после получения сообщения просто отправляет на сервак поддтверждение получения сообщения


 
Verg ©   (2004-03-23 08:38) [2]

Сходу могу только одно сказать.

> procedure Answ;
>  var
>    I: Integer;
>  begin
>    with ServerSocket.Socket do
>      for I := 0 to ActiveConnections - 1 do
>        Socket.Connections[I].SendText(Str);
>  end;
>  


 
Verg ©   (2004-03-23 08:40) [3]

Мфу ты, сам запутался


> Connections[I].SendText(Str);


Тут кто-то правильно говорил - забудьте про With - ошибок будет меньше


 
NAlexey ©   (2004-03-23 08:48) [4]

>Verg ©   (23.03.04 08:40) [3]
Здесь дело не в синтаксических ошибках, в оригинале все нормально. Ошибся я при составлении примера здесь, просто хотел передать принцип по которому все работает. Здесь дело в том, что при отсылке сообщения ф-ция CheckIfDeliver должна работать(по моему мнению), а она не работает. Т.е клиент отправил, другой при получении отправил подтверждение сервер разослал подтверждение всем клиентам они должны получить и обработать флаг Dilivered а моя ф-ция в это время ждет. Но этого не происходит, она ждет до конца.


 
Digitman ©   (2004-03-23 08:52) [5]


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


будет доставлено !
доставкой же занят не клиент, а системные транспортные механизмы .. ведь TCP/IP - транспортный протокол с гарантией доставки (говорят так же - с квитированием доставляемых пакетов) .. механизм доставки (с квитированием или без оного)прозрачен для прикладной клиентской задачи

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


> Все работает в асинхронном режиме


отсюда и проблемы твои

ты просто не учитываешь особенности работы гнезда в этом режиме
кр.того, ты не учитываешь особенности поточного протокола TCP/IP, наивно полагая, что данные (в твоем случае - строковые), отправленные передатчиком по SendText, на стороне приемника после выполнения ReceiveText будут иметь тот же вид


 
NAlexey ©   (2004-03-23 08:57) [6]

>Digitman ©   (23.03.04 08:52) [5]
>будет доставлено !
Странно, действительность показывает обратное. Если приложение занято достаточно долгое время, то сообщение просто не приходит, и отсылающий ничего не говорит. Да и в справке насколько я помню написано что OnRead при асинхронном режиме не всегда получает отправленные данные. И что надо чекать OnDisconnect.

>отсюда и проблемы твои
В чем заключаются эти проблемы?


 
Verg ©   (2004-03-23 09:07) [7]


> И что надо чекать OnDisconnect.


"Чекать" надо не только его. А что у тебя разрыв соединения происходит, что ли?

>  Да и в справке насколько я помню написано что OnRead при
> асинхронном режиме не всегда получает отправленные данные


Это в какой такой справке так написано? Покажи


 
NAlexey ©   (2004-03-23 09:11) [8]

>А что у тебя разрыв соединения происходит, что ли?
Разрыва не происходит. Просто если выполнить SendText занятому приложению оно не приходит и все.

>Это в какой такой справке так написано?
TCustomSocket.OnRead:
Note: Non-blocking sockets do not always receive an OnRead event for the last bit of data passed over the connection. When using a non-blocking socket, check for any unread data in the OnDisconnect event to make sure that everything is handled.


 
Digitman ©   (2004-03-23 09:14) [9]


> то сообщение просто не приходит


приходит ! а если не приходит, то связано это с буферизацией транспортируемых данных на стороне передатчика (со включенным по умолчанию алгоритмом Нагла), т.е. сообщение попросту не отправлено.. SendText() не есть факт физической отправки данных, это просто постановка данных в очередь передачи


> отсылающий ничего не говорит.


а что он, по твоему, должен "сказать" ? передатчик вызвал send, в рез-те чего данные, предназначенные к передаче, были поставлены в очередь, и получил назад управление .. далее же не его (передатчика) уже забота, как и в какие сроки эти данные будут доставлены стороне приемника


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


в справке не такого.. и быть не может

вот что там написано :

Occurs when a client socket should read information from the socket connection

should read information - здесь имеется ввиду, что следует вызвать один из recv-методов гнезда, чтобы прочитать некую очередную доступную (доставленную уже !) порцию поточной инф-ции


> И что надо чекать OnDisconnect


и такого нет в справке


> В чем заключаются эти проблемы?


в том, что ты наивно полагаешь, что если передатчик выполнил SendText("AAA"), то данные немедленно (уже якобы в ходе работы вызванного send-метода) будут доставлены гнезду-приемнику, и там будет возбуждено событие OnRead, в обработчике которого метод ReceiveText вернет в точности строку "AAA"


 
Verg ©   (2004-03-23 09:17) [10]

Ну так и что же там написано? А написано
>  check for any unread data in the OnDisconnect event to
> make sure that everything is handled


Но у тебя же НЕ происходит дисконнекта, как ты говоришь.


> Просто если выполнить SendText занятому приложению оно не
> приходит и все.


Т.е. ни OnError, ни OnDisconnect, но тем не менее не приходят?


 
NAlexey ©   (2004-03-23 09:24) [11]

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


 
Verg ©   (2004-03-23 09:31) [12]

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


>  Просто если выполнить SendText занятому приложению оно
> не приходит и все.


.... никогда не случится.


 
Digitman ©   (2004-03-23 09:52) [13]


> Правильный ли я избрал подход


в самой идее реализовать прикладное подтверждение доставки нет ничего криминального, но подход явно неверный ... ты не имеешь права делать какие-то предположения о предельном времени фактической доставки сообщения - это время, в общем случае, зависит от множества факторов, влиять на которые прикладной процесс, использующий IP-транспорт, практически не может (за исключением, наверно, манипуляций с алгоритмом Нагла)


> реально ли так получать ответ о получении сообщения


конечно реально ! только вот какое-то определенное время ожидания квитирующего сообщения устанавливать не следует

но здесь есть другой важный момент - сообщение физически было доставлено, но квитанция может и не прийти вообще из-за нештатного разрыва транспортного канала ... в этом случае принимающая сторона не получит ни OnRead, ни OnError ни OnDisconnect, хотя гнездо будет по прежнему выглядеть активным ..

для обнаружения такой ситуации можно задействовать/реализовать т.н. KeepAlive-механизм .. либо встроенный в установленный WSP (на уровне соотв.опции, см. SetSockOpt()) либо прикладной (если WSP не реализует встроенную возможность)

прикладной KeepAlive сводится к следующему : партнеру через равные промежутки времени посылается некое предопределенное тобой сообщение-"щуп" (на которые партнер может и не отвечать).. если в рез-те ходе такого сообщения (читай - вызов одного из send-методов гнезда) возникла исключительная ситуация ESocketConnectionError либо возникло событие OnError с соотв.кодом отказа, это говорит о нештатном разрыве транспортного канала (т.е. партнер не закрывал свою сторону соединения по своей же инициативе, а, например, компьютер партнера был отсоединен от сети физически).. далее ждать каких-то данных от партнера и продолжать с ним инф.обмен бессмысленно, следует тут же закрыть свою сторону соединения


> Нужно ли использовать синхронный режим, если да, то почему


необязательно... это зависит от логики, требуемой тебе

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

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

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


 
NAlexey ©   (2004-03-23 10:10) [14]

Спасибо за ответы, попробую изменить реализацию.



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

Текущий архив: 2004.05.16;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.063 c
7-1081502699
valera
2004-04-09 13:24
2004.05.16
Как программ.путем изменить букву логического диска?


14-1083052292
Slon_SCG
2004-04-27 11:51
2004.05.16
Автоматическое восстановление БД InterBase после сбоя


1-1082896888
sergg
2004-04-25 16:41
2004.05.16
Изменение одной строки в файле


7-1081242693
DmitryMN
2004-04-06 13:11
2004.05.16
Индикитор жесткого диска


4-1075492917
Xerx
2004-01-30 23:01
2004.05.16
создать виртуальный диск