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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.047 c
14-1082626816
}|{yk
2004-04-22 13:40
2004.05.16
22 апреля - день рождения В.И.Ульянова


8-1078273036
Jaine
2004-03-03 03:17
2004.05.16
Смена иконки (Glyph) на кнопке типа BitBtn or Speedbutton


7-1081354283
beard
2004-04-07 20:11
2004.05.16
Работа с АТС через TAPI


14-1082704568
Goida
2004-04-23 11:16
2004.05.16
Баги в Delphi7


4-1080544622
Akvilon
2004-03-29 11:17
2004.05.16
окно выбора папки





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский