Форум: "Сети";
Текущий архив: 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.OnConnectProcedure 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, после того как клиент заново загрузился. Добавляем его в список ClientsClients.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.071 c