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

Вниз

TIdTCPServer: Восстановление коннекта   Найти похожие ветки 

 
Сатир   (2007-06-12 16:16) [0]

Есть шлюз, который обговаривался в этих ветках:
http://delphimaster.net/view/15-1179906322/
http://delphimaster.net/view/15-1179906322/
Произвел переход на Indy 10.
Также произвел легкий рефакторинг кода, разделив на два независимых сервиса.
Но главная проблемма так и осталась: после перезагрузки удалённой системы сабж не видит текущий коннект и считает, что связи нету.
А теперь подробней, как это выглядит в коде:
есть такая структура для хранения активных коннектов

Type
 PClient = ^TClient;
 TClient = Record // Object holding data of client (see events)
   DNS: String[20]; { Hostname }
   Connected, { Time of connect }
   LastAction: TDateTime; { Time of last transaction }
   Thread: Pointer; { Pointer to thread }
   Context: TIdContext;
 End;

есть
переменная класса Clients:TThreadList, в которой хранятся указатели на активные коннекты
Заполнение этой структуры происходит в методе idTCPServer.OnConnect
Procedure TSentDM.IdTCPServerConnect2(AContext: TIdContext {AThread: TIdPeerThread});
Var
 NewClient: PClient;
Begin
 Try
   TidThread(AContext.Yarn).Synchronize(ShowServerConnect);

   GetMem(NewClient, SizeOf(TClient));
   NewClient.DNS := GetCompName {IdTCPServer.LocalName};
   NewClient.Connected := Now;
   NewClient.LastAction := NewClient.Connected;
   NewClient.Thread := AContext.Yarn;
   // NewClient.Connection := AContext.Connection;
   NewClient.Context := AContext;

   AContext.Data := TObject(NewClient);

   Try
     Clients{IdTCPServer.Contexts}.LockList.Add(NewClient);
   Finally
     Clients{IdTCPServer.Contexts}.UnlockList;
   End;
   
 Except
   On E: Exception Do
     DM.WriteTMPlog("Error");
 End;
End;


на событии дисконнекта происходит следующее:

Procedure TSentDM.IdTCPServerDisconnect2(AContext: TIdContext {AThread: TIdPeerThread});
Var
 ActClient: PClient;
Begin
 Try
   TIdThread(AContext.Yarn).Synchronize(ShowServerDisConnect);

   ActClient := PClient(AContext.Data);
   SetConnectionStatus(1, 0);
   Try
     Clients{IdTCPServer.Contexts}.LockList.Remove(ActClient);
   Finally
     Clients{IdTCPServer.Contexts}.UnlockList;
     FreeMem(ActClient);
   End;
   AContext.Data := Nil;
except
  //log error
end
end;

и само использование активного коннекта происходит таким образом:

Function TSentDM.SendXMLfile(FilePath: String): TBackMsg;
Var
 FileStrim: TFileStream;
 RecClient: PClient;
 Context: TIdContext;
 i: integer;
 AStream: TIdStreamVCL;
Begin
 Try

   With Clients{IdTCPServer.Contexts}.LockList Do
   Begin
     For i := 0 To Count - 1 Do // iterate through client-list
     Begin
       RecClient := Items[i]; // get client-object

       If Not RecClient.Context.Connection.Connected Then
         Begin
           Вот это не помогает. Используемый контекст считает, что он всё ещё не активен. Как создать новый контекст подключения, чтобы использовать его для пересылки файла?
           IdTCPServer.Active := true;
                 
         End;

       FileStrim := TFileStream.Create(FilePath, fmOpenReadWrite);

       AStream := TIdStreamVCL.Create(FileStrim);
       Try
         FileStrim.Position := 0;
         RecClient.Context.Connection.IOHandler.WriteBufferOpen;
         Try
           RecClient.Context.Connection.IOHandler.Write(AStream);
           Try
             RecClient.Context.Connection.IOHandler.WriteBufferFlush;
           Except
             IdTCPServerDisconnect2(RecClient.Context);
           End;
         Finally
           RecClient.Context.Connection.IOHandler.WriteBufferClose;
         End;

         Result.ID := 1;
         Result.Msg := "W: Файл успешно отправлен: " + ExtractFileName(FilePath);
       Finally
         FileStrim.Free;
         //  RecThread.Free;
       End;
     End;
   End;
   If Clients{IdTCPServer.Contexts}.LockList.Count = 0 Then
   Begin
     Result.ID := 0;
     Result.Msg := "E: Файл: " + ExtractFileName(FilePath) +
       " не отправлен так как нет актиных конектов";
   End;
 Except
   On E: Exception Do
   Begin
     Result.ID := -1;
     Result.Msg := "E: Ошибка процедуры [SendXMLfile]: " + E.Message;
   End;
 End;
End;


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


 
Сергей М. ©   (2007-06-13 08:48) [1]


> как пересоздать контекст соединения


А никак.
Инициатором соединения является клиент, а не сервер.


 
Сатир   (2007-06-13 10:31) [2]


> Инициатором соединения является клиент, а не сервер.

Вот он(клиент) его и пересоздаёт после своей перегрузки.
Но сервер держит старый контекст и не даёт новому стать на его место.


 
Сергей М. ©   (2007-06-13 10:50) [3]


> не даёт новому стать на его место


И не даст.

Новое соединение - это новый контекст, не имеющий отношения к контексту прежнего, уже несуществующего соединения.


 
Сатир   (2007-06-13 12:23) [4]


> Новое соединение - это новый контекст, не имеющий отношения
> к контексту прежнего, уже несуществующего соединения.

Объясняю проблемму:
Самое первое соединение - Context1 добавили в Clients, всё нормально работает.
Потом клиент перегружается, происходит дисконнект, ссылка на первый контекст из Clients удаляется
вот код, который это делает:
Clients.LockList.Remove(ActClient);
потом происходит второе соединение - Context2, после того как клиент заново загрузился. Добавляем его в список Clients
Clients.LockList.Add(NewClient);
и после этого пытаемся его использовать для отправки файлов
но оказывается, что он не активен, потому что зрабатывает это условие
If Not RecClient.Context.Connection.Connected Then

Где логика?


 
Сергей М. ©   (2007-06-13 12:38) [5]


> и после этого


Что значит "после этого" ?
Прямо в обработчике OnConnect ?


 
Сатир   (2007-06-13 13:20) [6]


> Прямо в обработчике OnConnect ?

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


 
Сергей М. ©   (2007-06-13 13:37) [7]

Т.е. метод SendXMLfile вызывается в теле обработчика таймера ?


 
Сатир   (2007-06-13 15:02) [8]


> Т.е. метод SendXMLfile вызывается в теле обработчика таймера
> ?

в теле обработчика вызывается метод, который выполняет пакет заданий, в том числе и SendXMLfile


 
Сергей М. ©   (2007-06-13 15:21) [9]

Так..

И ты утверждаешь, что в момент вызова SendXMLfile в твоем списке Clients все его элементы ссылаются на контексты not-connected-соединений ?


 
Сатир   (2007-06-13 15:59) [10]

Да, это видно под отладчиком.
Он берёт первый элемент из этого списка, пытается в его контексте отправить файл и вываливается по ошибке.
Но ведь во время дисконнекта, неактивный контекст должен был быть удалён из этого списка, что следует из

> Try
>      Clients{IdTCPServer.Contexts}.LockList.Remove(ActClient);
>
>    Finally
>      Clients{IdTCPServer.Contexts}.UnlockList;
>      FreeMem(ActClient);
>    End;

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

Try
     Clients.LockList.Remove(ActClient);
     Clients.LockList.Clear;
   Finally
     Clients.UnlockList;
     FreeMem(ActClient);
   End;
 

но когда прошёлся под отладчиком по этому куску, после этой строки
     Clients.LockList.Remove(ActClient);
отладчик передал управление программе и не перешёл на следующую строку.
При этом, никакого сообщение об ошибке не возникло.
Посему, у меня возникло предположение, что неактивный контекст не был удален из списка активных контекстов.


 
Сергей М. ©   (2007-06-13 16:38) [11]


> отладчик передал управление программе и не перешёл на следующую
> строку


Значит возникло исключение.


 
Сатир   (2007-06-13 16:47) [12]


> Значит возникло исключение.


> При этом, никакого сообщение об ошибке не возникло.

В отладчике стоит птица "Stop on Delphi Exceptions"


 
Сергей М. ©   (2007-06-13 16:55) [13]


> после этой строки


Что значит "после" ?

Может быть при ее выполнении ?

Изволь выражаться точнее ..

Потому что "после" - это строка с Clear ...


 
Сатир   (2007-06-13 17:01) [14]


> Может быть при ее выполнении ?

да-да, верно. При её выполнении, передаётся управление программе.
То есть, я стою на строке Remove, нажимаю F8 и программа молчаливо продолжает работать, хотя должна остановиться на строке Clear.
Чтобы это могло значить?
Никаких замечаний от среды отладки не поступало...


 
Сатир   (2007-06-13 17:33) [15]

Пробовал заменить TThreadList на обычный TList(у меня только один клиент и возможно только одно соединение), чтобы нормально удалять из него указатели, но оказалось, что это повлекло за собой кучу ошибок в индийском коде в районе метода DoDisconnect
На что ещё можно заменить TThreadList и возможно ли сделать соединение без использования потоков?


 
Сатир   (2007-06-13 18:02) [16]

поменял TThreadList на TIdThreadSafeList.
Но всё равно в методе дисконнекта выдает кучу ошибок...


 
Сергей М. ©   (2007-06-14 08:27) [17]

А где обработка потенциальных исключений в обработчике OnDisconnect ?

Что-то я не вижу ее ..

except
// log error <-- здесь должно быть реальное протоколирование исключений
end;

?



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

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

Наверх




Память: 0.5 MB
Время: 0.043 c
2-1202578462
DDR
2008-02-09 20:34
2008.03.09
Поиск файлов и TreeView


2-1202901337
olega
2008-02-13 14:15
2008.03.09
Зарпет обработки события


2-1202796912
жорик
2008-02-12 09:15
2008.03.09
открыт ли файл


15-1202066029
Неважно
2008-02-03 22:13
2008.03.09
Альтернатива GSM-модему


9-1167303712
megabyte-ceercop
2006-12-28 14:01
2008.03.09
Установить DelphiX на C++Builder





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