-
Уважаемые специалисты! Нужна помощь. Delphi 7. Трехзвенная архитектура.
Сервер приложений - RemoteDateModule, клиент - SocketConnection.
Краткое описание системы: Имеется несколько деканатов. В деканате может быть несколько
компьютеров, на которых установлены серверы приложений на основе RemoteDateModule
(например, свой компьютер на каждую форму обучения).
Кроме того, один сервер приложений может соединяться с несколькими файлами БД
(например, для каждой группы специальностей свой файл БД). В качестве БД используется
FireBird. Пути к доступным файлам БД хранятся в ini-файле.
Клиент (учебный отдел, проректор и т.п.) имеет свою локальную БД, в которую
записываются различные сводные данные, импортируемые с факультетов.
В этой БД имеются также данные о компьютерах факультетов (IP-адреса и т.п.).
Для соединения с сервером приложений используется SocketConnection.
Задача в следующем. Необходимо реализовать импорт данных со всех компьютеров
и со всех доступных файлов БД факультета.
Вариант решения: Из локальной БД клиента запрос (компонент DSetComps) предоставляет
список компьютеров факультета. С каждым компьютером по очереди выполняется соединение
и запрашивается список доступных файлов БД (метод интерфеса GetBDFiles). Затем поочередно
с помощью метода ConnectFile серверу передается путь к файлу БД, из которого
надо импортировать данные. ConnectFile записывает этот путь в соответствующее свойство
компонента IBDatabase.
Фрагмент кода тонкого клиента:var
BDFiles,FilePath:WideString;
FacBDFiles:TStringList;
begin
...
dmLocalBD.DSetComps.First;
while not dmLocalBD.DSetComps.Eof do
begin
dmClient.SocketCon.Close;
dmClient.SocketCon.Address:=dmLocalBD.DSetCompsIPADDR.AsString;
try
FacBDFiles:=TStringList.Create;
FacBDFiles.Clear;
dmClient.SocketCon.AppServer.GetBDFiles(BDFiles);
FacBDFiles.Text:=BDFiles;
except
...
end;
for i:=0 to FacBDFiles.Count-1 do
begin
try
dmClient.SocketCon.AppServer.ConnectFile(FilePath);
ImpData; //Импорт данных
except
...
end;
end;
dmLocalBD.DSetComps.Next;
end;
dmClient.SocketCon.Close;
end;
Методы интерфейса сервера приложений:procedure TAppServerDec.GetBDFiles(out BDFiles: WideString);
var
Lst:TStringList;
IniFile:TMemIniFile;
begin
Lst:=TStringList.Create;
Lst.Clear;
IniFile:=TMemIniFile.Create(ExtractFilePath(Application.ExeName)+'Decanat.ini');
IniFile.ReadSectionValues('RemoteAccess',Lst);
BDFiles:=Lst.Text;
Lst.Free;
IniFile.Free;
end;
procedure TAppServerDec.ConnectFile(const FilePath: WideString);
begin
if IBDatabase.Connected
then IBDatabase.Close;
IBDatabase.DatabaseName:=FilePath;
end;
Проблема в следующем. Импорт с первого компьютера происходит норамально.
При переходе ко второму компьютеру метод GetBDFiles тоже успешно передает
список БД, а вот при выполнении метода ConnectFile возникает исключительная
ситуация со следующим сообщением:
Project raised exception class Exception with message 'Access violation
at address 0048B9F6 in module 'ScktSrvr.exe'. Read of address 00000000.
Это моя ошибка или глюк в ScktSrvr.exe, поскольку с DCOMConnection
все работает норамально? Как это все исправить для SocketConnection?
Заранее благодарен за ответы. -
Сергей М. © (10.10.09 13:04) [1]
> at address 0048B9F6
Этот адрес указывает на вполне определенную строчку исх.текста приложения scktsrvr.exe.
Воспользуйся встр.отладчиком для локализации строчки-источника исключения
см. меню IDE "Search -> Find Error .." -
Дело в том, что ScktSrvr.exe поставляется вместе с Delphi. И я не силен в тонкостях работы сокетов, чтобы модифицировать его исходный код. Может быть есть какие-либо другие подходы? Или придется отказаться от применения SocketConnection.
-
Сергей М. © (10.10.09 16:47) [3]
> ScktSrvr.exe поставляется вместе с Delphi
Приложение ScktSrvr поставляется с исходными текстами.
Его, как и любое другое приложение, можно пересобрать со включенными отлад.опциями и запустить под управлением встр.отладчика, тогда меню IDE "Search -> Find Error .." поможет локализовать проблему, даже если ты не силен в тонкостях работы сокетов. -
Сергей М. © (10.10.09 16:52) [4]
> при выполнении метода ConnectFile возникает исключительная
> ситуация
Кр.того, в теле метода ConnectFile сокетами даже не пахнет. -
Спасибо, Сергей М., за активную попытку мне помочь. Попробую еще повозиться. Дело в том, что исключение возникает не при выполнении ConnectFile, а при попытке его выполнения, т.е. до метода пройесс не доходит. Вторая проблема у меня в том, что раньше мне не приходилось отлаживать взаимодейтсвующие процессы из разных проектов. Пытаюсь это освоить. Но пока получаю только ассемблерный код, а до исходников не могу добраться. Буду биться дальше.
-
Сергей М. © (10.10.09 17:28) [6]
> при попытке его выполнения
Что значит "при попытке" ?
Откуда ты узнал что при попытке, а не во время ? -
При пошаговой отладке, когда все нормально, операторdmClient.SocketCon.AppServer.ConnectFile(FilePath)
при нажатии F8 переходит на следующую строку кода. Когда возникает исключение от ScktSrvr, нажатие F8 не приводит к переходу к следующей строке. При этом параметр FilePath становится пустой строкой. Следующее нажатие F8 повторяет выполнение этого же оператора. Из этого я и решил, что до самого метода процесс не доходит. Кстати непосредственно перед возникновением ошибки, пропадает доступ к AppServer. -
Сергей М. © (10.10.09 19:11) [8]А scktsrvr.exe при этом работает на той же самой машине ?
-
Сейчас пробую все на одной машине. Но пробовал и в сети, когда на каждом сервере приложений свой scktsrvr.exe. Клиент пытается опрашивать все серверы, но картина получается такая же, та же ошибка.
-
Проблему решил. Если кто столкнется с такой ситуацией, данное решение может пригодиться (возможно и не самое идеальное, но все работает нормально).
Обращения к методам интерфейса включил в специальные процедуры, в которых параметры BDFiles и FilePath локальные.procedure GetSpDBFiles(var Files:TStringList);
var
BDFiles:WideString;
begin
dmClient.SocketCon.AppServer.GetBDFiles(BDFiles);
Files.Text:=BDFiles;
end;
procedure SetFilePath(FilePath:WideString);
begin
dmClient.SocketCon.AppServer.ConnectFile(FilePath);
end;
Вместо обращения к методам интерфейсаdmClient.SocketCon.AppServer.GetBDFiles(BDFiles)
dmClient.SocketCon.AppServer.ConnectFile(FilePath);
реализовал обращение к соответствующим процедурамGetSpDBFiles(FacBDFiles)
SetFilePath(FilePath)
В результате получается следующий фрагмент
кода:var
FilePath:WideString;
FacBDFiles:TStringList;
begin
...
dmLocalBD.DSetComps.First;
while not dmLocalBD.DSetComps.Eof do
begin
dmClient.SocketCon.Close;
dmClient.SocketCon.Address:=dmLocalBD.DSetCompsIPADDR.AsString;
try
FacBDFiles:=TStringList.Create;
FacBDFiles.Clear;
GetSpDBFiles(FacBDFiles);
except
...
end;
for i:=0 to FacBDFiles.Count-1 do
begin
try
SetFilePath(FilePath);
ImpData; //Импорт данных
except
...
end;
end;
dmLocalBD.DSetComps.Next;
end;
dmClient.SocketCon.Close;
end;
Объяснить это могу только тем, что параметры, используемые в методах интерфеса видимо должны быть локальными. -
Сергей М. © (11.10.09 17:41) [11]Ерунда какая-то ..
-
В том-то и дело, что ерунда какая-то, но работает. Спасибо, Сергей М., за помощь.
-
Сергей М. © (12.10.09 10:06) [13]
> Импорт с первого компьютера происходит норамально.
> При переходе ко второму компьютеру метод GetBDFiles тоже
> успешно передает
Как это вообще работало - уму не постижимо)
Метод GetBDFiles у тебя ожидает формальным параметром тип WideString, а ты ему впариваешь тип TStringList .. -
> Метод GetBDFiles у тебя ожидает формальным параметром тип
> WideString, а ты ему впариваешь тип TStringList ..
Почему TStringList? Патасетр объявлен как WideStrig:var
BDFiles:WideString;
Кстати, как в исходном вопросе, так и в работающем варианте пропущена строкаFilePath:=FacBDFiles.ValueFromIndex[i];
которая выполняется непосредственно перед обращением к методуdmClient.SocketCon.AppServer.ConnectFile(FilePath); -
Извините, поторопился, нажал не те клавиши. В предыдущем сообщении не патасетр, а параметр. В следующий раз буду внимательнее. Как исправить уже отправленное сообщение, не знаю.
-
Сергей М. © (12.10.09 16:24) [16]А, ну да ..
Пардон, параметр передается действительно требуемого типа.
Ну тогда еще одно замечание (не связанное непосредственно с проблемой) - нет никакой нужды чистить (Clear) стринглист сразу после его создания, он создается уже пустым. -
Спасибо, Сергей М., за совет. Сидит во мне какой-то синдром перестраховки, поэтому на всякий случай и чищу стринглист. На будущее учту.