2016-04-15 12 views
1

Я создал автономный TCP/IP-сервер Datasnap с помощью Мастера. Я выбрал образцы методов (эхострим и реверсивность). Я сохранил сервер и запустил его. Затем я создал клиентское приложение и использовал файл-новый-другой, добавленный ClientModule к этому проекту клиента, а также блок ClientClasses. На основной форме. Я добавил кнопку. На OnClick обработчик события кнопки, я добавил следующий код:Ошибка Delphi 10 Seattle Datasnap: «Не удалось выполнить операцию. Соединение было закрыто».

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if ClientModule1.SQLConnection1.Connected then 
    begin 
    Button1.Text := 'Open'; 
    ClientModule1.SQLConnection1.Close; 
    end 
    else 
    begin 
    Button1.Text := 'Close'; 
    // ClientModule1.SQLConnection1.Open; 
    ClientModule1.ServerMethods1Client.ReverseString('myteststring'); 
    end; 
end; 

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

Вы можете видеть, что я прокомментировал Connection.Open, потому что первый вызов ServerMethods1client открывает соединение. Сгенерированный код показан здесь:

function TClientModule1.GetServerMethods1Client: TServerMethods1Client; 
begin 
    if FServerMethods1Client = nil then 
    begin 
    SQLConnection1.Open; 
    FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, FInstanceOwner); 
    end; 
    Result := FServerMethods1Client; 
end; 

Теперь проблема возникает. При первом нажатии на кнопку соединение открывается и вызывается метод. При втором нажатии кнопки соединение закрывается. На третьем клике возникает исключение «Операция с ошибкой. Соединение закрыто» с помощью кода TDBXCommand.

В качестве обходного пути, я попытался это:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if ClientModule1.SQLConnection1.Connected then 
    begin 
    Button1.Text := 'Open'; 
    ClientModule1.SQLConnection1.Close; 
    ClientModule1.ServerMethods1Client := nil; 
    end 
    else 
    begin 
    Button1.Text := 'Close'; 
    // ClientModule1.SQLConnection1.Open; 
    ClientModule1.ServerMethods1Client.ReverseString('myteststring'); 
    end; 
end; 

Это бы-решить эту проблему, так как экземпляр FServerMethods1Client в ClientModule1 является сброс поэтому создать код работает снова, как это было на первом плане.

Единственная другая проблема сейчас, это (я использую Eurekalog), она создает утечку памяти.

Что я делаю неправильно? Каков правильный способ подключения/отключения от сервера Datasnap, не перезагружая приложение?

ответ

-1

В моей реализации Android FMX я только называю методы сервера, чтобы все было сделано. (т.е. я не использую компоненты данных Datasnap). Слишком много неконтролируемой передачи данных накладные расходы на архитектуру Datasnap, чтобы рассмотреть что-либо еще реально на мобильном устройстве ...Чтобы обойти это (и не иметь утечек памяти), я теперь создавать локальные экземпляры в TServerMethods1Client, как и когда они нужны мне и освободить их в контексте:

function TClientModule1.PostTheLog: Boolean; 
var 
    Server: TServerMethods1Client; 
begin 

    Server := TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection); 
    try 
     UserID := Server.GetUserID; 
     ... 
    finally 
     Server.Free; 
    end; 
end; 

Теперь ClientModule1.SQLConnection1 можно подключать и отключать при (предпочтительно подключается непосредственно перед любым вызовом к серверному методу и затем отключается), и никаких дополнительных проблем не возникает.

Который затем задает вопрос: в каком идеальном мире был бы полезен общедоступный ServerMethods1Client?

+0

Это работает, хотя было бы более эффективно поддерживать экземпляр прокси-сервера клиента при условии, что соединение открыто, а не создавать и уничтожать новый экземпляр каждый раз. Распределение/управление памятью дорого, особенно по сравнению с альтернативой (не повторяя это). –

+0

Я смущен тем, что вы ответили на свой вопрос и отметили его как ответ, когда предоставленная вами информация действительно не является ответом на исходный вопрос. –

+0

Вы, конечно же, можете получить полный ответ. Между тем, мой собственный ответ достаточно, не так ли? – nolaspeaker

2

Причина первой ошибки заключается в том, что код, который связывает прокси-сервер на стороне клиента (который позволяет вызвать методы сервера), привязан к локальному соединению SQL. Обратите внимание на вызов, чтобы создать прокси-класс:

FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, ...) 

Соединение основной DBExpress передается по ссылке, и прокси-класс использует это соединение для вызова сервера. Вы закрыли и повторно открыли соединение, но базовое соединение DBExpress, используемое ServerMethodsClient1, было уничтожено. Таким образом, вы получаете исключение «Соединение было закрыто». Соединение, которое ServerMethodsClient1 использовало, было закрыто. Вам необходимо воссоздать ServerMethodsClient1, как и во втором примере.

Я не могу ответить на ваш второй вопрос, так как я считаю, что это ARC. Для приложения VCL DataSnap я бы назвал ServerMethodsClient1.Free, а не установил его на нуль. Основываясь на моем очень, очень ограниченном понимании реализации ARC Delphi (все это из групп новостей), я считаю, что вы должны назвать ServerMethodsClient1.DisposeOf, поскольку класс спускается с TComponent

Но я не уверен в этом. Я уверен, что кто-то скачет сюда, понимает ARC и правильное решение для уничтожения объекта, а не утечки памяти.

+0

Спасибо. То, что вы сказали, имеет смысл ... до определенной степени. Я на самом деле написал полные приложения Vat datasnap, которые используются каждый день, и я никогда не сталкивался с этой проблемой. Почему нет? Потому что я использовал компоненты времени разработки (TDSProviderConnection и TSqlServerMethod) для получения данных с этого сервера. Обновления выполняются с помощью соответствующего TClientDataset.Applyupdattes. Я не называю какие-либо серверные методы и в этой реализации, и пользователи подключаются и отключаются весь день, не закрывая приложение. Подробнее ... – nolaspeaker

 Смежные вопросы

  • Нет связанных вопросов^_^