Nesse artigo veremos como desenvolver a aplicação cliente para a aplicação servidor que criamos no artigo anterior.
Aplicação Cliente
Aplicação cliente é um programa que solicita informações para um programa servidor, por isso do nome. A Aplicação Cliente fica nas estações, é o programa no qual o usuário terá contato, o cliente faz uma solicitação de dados ao Aplicativo Servidor que analisa essa solicitação e devolve em pacotes os dados solicitados.
Como funciona?
O aplicativo cliente se conecta ao Remote DataModule na Aplicação Servidora, ativando o servidor caso não esteja ativado, quando o cliente se conecta ao Remote DataModule é criado uma instância* desse Remote DataModule para atender a solicitação da Aplicação Cliente.
Criada a instância, a Aplicação Cliente faz solicitação de algum dado para essa instância que foi criada, então essa instância empacota os dados solicitados e devolve para a Aplicação Cliente. Esses dados passam a ficar na memória e toda e qualquer alteração não é efetivada diretamente no Banco de dados, a Aplicação Cliente deve enviar um ApplyUpdates desses dados para a instância do Remote DataModule, que foi criada para ela, para que ela faça a atualização efetiva no Banco de dados.
Criando a aplicação cliente
Conectando a Base de dados
Na nossa aplicação cliente terá uma tela para operações básicas com uma tabela como Incluir, Excluir, Consultar e etc.
Inicie uma nova aplicação Delphi e coloque um DataSource, ClientDataSet e um SocketConnection que está na paleta DataSnap*.
Com o SocketConnection, nós conectamos ao Servidor de aplicação para ter acesso aos dados que disponibilizamos. Selecione-o e no campo Address coloque o IP da máquina que tem o Servidor de aplicação, no nosso caso podemos usar o endereço de loop back que é: 127.0.0.1. em ServerName escolha o servidor de aplicação que nós criamos que é: ServerApplication.Server.
Selecione o ClientDataSet e vá na propriedade RemoteServer e escolha o SocketConnection que acabamos de configurar, e na propriedade ProviderName escolha o nome do DataSetProvider que está na aplicação Servidora que é o dspClientes, mude a propriedade Name para cdsClientes. Dê um duplo clique no ClientDataSet e pressione CTRL + F para adicionar todos os campos. Depois de adicionar os campos, você pode selecionar um a um e mudar a propriedade DisplayLabel, que é a forma que será exibido o nome dos campos para o usuário.
Selecione o DataSource e na propriedade DataSet escolha o cdsClientes, mude o nome do DataSource para dsClientes.
Vamos salvar nossa aplicação. Clique em File e Save All ou CTRL + SHIFT + S, crie uma pasta e salve a Unit com o nome untClientes e dê ao projeto o nome de ClientApplication.
Agora que a nossa estrutura de acesso a dados está pronta vamos criar a tela para interação com o usuário.
Desenhando o formulário
Dê um duplo clique no ClientDataSet e arraste os campos para o formulário, perceba que os rótulos já vem de acordo com o que definimos em DisplayLabel. Coloque um Toolbar nesse formulário também, clique com o botão direito na Toolbar e escolha New button, coloque 6 botões e um Separator, também usando o botão direito.
Insira mais 4 botões e um Separator e mais dois botões. Coloque também um StatusBar, mude a propriedade SimplePanel para True. Se tudo estiver OK a tela deve ficar parecida com a mostrada abaixo:

Criando uma lista de imagens
Coloque na aplicação um ImageList, esse componente permite criarmos uma lista de imagens para usarmos na nossa aplicação. Dê um duplo clique nele, vai aparecer a tela Form1.ImageList1 ImageList, clique no botão Add... e localize onde as figuras se encontram para adicioná-las na lista, escolha as figuras baseado nas ações abaixo. Depois de adicionar todas as imagens clique em OK.
Criando Actions
Coloque um componente ActionList, esse componente permite centralizarmos as rotinas das nossas aplicações. Na propriedade Images desse componente selecione o ImageList.
Dê um duplo clique no ActionList, vai aparecer uma tela como a mostrada abaixo:

Pressione CTRL + Ins ou dê um clique na seta ao lado do botão New Action e escolha New Standard Action, como mostrado abaixo:

Será exibida a tela abaixo:

Na tela Standard Action Classes, procure o grupo DataSet, como mostrado acima. Nesse grupo, temos um conjunto para operação com registros, a que estamos acostumados a usar, observe que todas as rotinas para trabalhamos com um registros já estão prontas.
Clique em TDataSetFirst1, segure a tecla Shift, clique em TDataSetRefresh e em OK. Ao clicar em OK, ele volta para a tela Editing Form1.ActionList1 com maior parte das funções que usaremos nesse projeto definidas, agora selecione-as e na propriedade DataSource e escolha o dsClientes é dessa forma que as funções sabem em qual DataSet realizar as operações. Agora, para cada Action, escolha uma imagem em ImageIndex.
Em Categories*, clique em (No Category), clique no botão New Action ou pressione Ins e para essa Action dê o nome Localizar e em Category digite Funções, será criada uma nova categoria, e em ImageIndex escolha uma figura, crie outra Action com o nome Sair e associe na categoria Funções e escolha uma figura também. Clique duas vezes na ação Sair e digite o comando Close, se quiser pode perguntar ao usuário se ele deseja realmente fechar o formulário. Agora clique duas vezes na ação Localizar e digite o código abaixo:
procedure TForm1.LocalizarExecute(Sender: TObject);
var
Fantasia : String;
begin
if not(cdsClientes.Filtered) then // Se estiver Filtrado
cdsClientes.Filtered := False // Remove o filtro
else // Se não estiver filtrado
begin
Fantasia := InputBox('Localizar', 'Digite o nome Fantasia', '');
cdsClientes.Filtered := False; // Remover filtro, caso tenha algum, se não fizer isso ocorre um erro
cdsClientes.Filter := 'Fantasia=' + QuotedStr(Fantasia + '*'); { Com o asterisco é permitido procurar por parte do texto}
cdsClientes.Filtered := True // Aplica o novo filtro definido na propriedade Filter
end // else if not(cdsClientes.Filtered)
end;
Associando os Actions
Nós temos 12 ações, agora vamos associá-las aos botões definidos na ToolBar. Antes de associá-las, selecione a ToolBar e em Images escolha o componente ImageList1, senão as figuras que associamos com as Actions não aparecem. A lista abaixo indica que botão será associado com qual ação, você vai fazer essa associação usando a propriedade Action do botão.
|
Ordem do Botão
|
Action
|
|
1º
|
DataSetInsert1
|
|
2º
|
DataSetEdit1
|
|
3º
|
DataSetPost1
|
|
4º
|
DataSetDelete1
|
|
5º
|
DataSetCancel1
|
|
6º
|
DataSetRefresh1
|
|
7º
|
DataSetFirst1
|
|
8º
|
DataSetPrior1
|
|
9º
|
DataSetNext1
|
|
10º
|
DataSetLast1
|
|
11º
|
Localizar
|
|
12º
|
Sair
|
Se tudo estiver OK, a sua tela deve estar parecida com a mostrada abaixo, as diferenças são as figuras usadas:

Dê um duplo clique no formulário e digite a seguinte instrução:
procedure TForm1.FormCreate(Sender: TObject);
begin
cdsClientes.Open
end;
Com essa instrução, além de abrir a tabela nós também ativamos o SokectConnection. Selecione o cdsClientes e no evento AfterPost digite a instrução abaixo:
procedure TForm1.cdsClientesAfterPost(DataSet: TDataSet);
begin
cdsClientes.ApplyUpdates(-1)
end;
Ou seja, toda vez que o usuário clicar no botão salvar, será dado um Post no cdsClientes e toda vez que esse post for realizado será chamada a função ApplyUpdates, que nada mais nada menos concretiza as alterações feitas pelo usuário no banco de dados, dentro dos parênteses indica a quantidade de erros que é suportada ao aplicar os dados no banco de dados, -1 é para não aceitar nenhum erro.
Agora no evento OnReconcileError do cdsClientes, vamos programar para que quando der algum erro na hora de aplicar as alterações do banco de dados, exiba uma mensagem com a descrição do que aconteceu. Digite no evento OnReconcileError a seguinte instrução:
procedure TForm1.cdsClientesReconcileError(DataSet: TCustomClientDataSet;
E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);
begin
ShowMessage('Não foi possível aplicar as alterações' + #13#10 +
'Erro: ' + E.Message);
Action := raCancel // Cancela as alterações para o registro
end;
Esse evento ocorre toda vez que houve problemas na atualização de um registro. Nós programamos para que toda vez que o usuário salvar os dados (Post) também aplicar as alterações no banco (ApplyUpdates), poderíamos aplicar as alterações quando o formulário fechasse, por exemplo, aplicando assim todas as alterações de uma vez e não toda hora como ocorre nessa aplicação.
Como é para fins de exemplo e aprendizado o que nós estamos fazendo é bem válido, a partir de então fica a seu critério caro leitor de implementar na maneira como achar conveniente. No parâmetro Action desse evento colocamos raCancel, isso significa que as alterações para esse registro serão canceladas, observem que é somente para o registro que apresentou algum tipo de problema de consistência, campo em branco por exemplo.
Agora só falta criamos a tela de Login. Vamos lá.
Coloque na nossa aplicação mais um formulário, clicando em File > New > Form – Delphi for Win32. Coloque a propriedade BorderStyle para bsDialog. Deixe sua tela parecida com a apresentada abaixo:

O botão Login coloque a propriedade Default para True e o botão Sair coloque a propriedade Cancel para True. Com a propriedade Default True o usuário pode acionar o botão pressionando a tecla Enter e com a propriedade Cancel True o usuário aciona o botão pressionando a tecla Esc. Apague a propriedade Text do Edit deixando-o em branco.
Vá em Project à Options, ou pressione as teclas Ctrl + Shift + F11. Em Auto-create forms, deixe somente o Form1. O outro formulário criaremos em Run-time.
Clique no menu File e escolha Use Unit, ou pressione Alt + F11, escolha a untClientes para que possamos ter acesso ao componente SocketConnection.
Clique duas vezes no botão de Login e adicione a instrução abaixo:
procedure TForm2.BitBtn1Click(Sender: TObject);
begin
if (Edit1.Text <> '') then
Form1.SocketConnection1.AppServer.Login(Edit1.Text, '')
else
begin
ShowMessage('Digite o nome de usuário');
Edit1.SetFocus;
Exit
end; // else do if (Edit1.Text <> '')
Form1.StatusBar1.SimpleText := Edit1.Text;
Close
end;
Através da propriedade AppServer do SokectConnection, podemos acessar todos os métodos criados no nosso servidor de aplicação. Então nós colocamos o método Login que criamos no servidor. Observe que colocamos o nome do usuário digitado no Edit e, no local onde seria a senha, deixamos em branco. Isso por que deixamos implementado no servidor, mas não fizemos nenhuma validação com a senha, justamente para ficar a seu critério fazer alguma validação ou verificação.
No botão Sair, digite o código abaixo:
procedure TForm2.BitBtn2Click(Sender: TObject);
begin
Application.Terminate
end;
Ou seja, se ele não fizer o Login, a aplicação é fechada. No evento OnCreate do Form1 digite a seguinte instrução:
procedure TForm1.FormCreate(Sender: TObject);
begin
SocketConnection1.Open;
Form2 := TForm2.Create(Self);
Form2.ShowModal;
cdsClientes.Open
end;
E no evento OnClose, digite a instrução abaixo:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
SocketConnection1.AppServer.Logout(StatusBar1.SimpleText)
end;
Quando o usuário fechar o formulário dar um Logout para liberar o usuário, lembre-se que a validação que nós fizemos limita a quantidade de usuários logados na aplicação.
Pronto! Agora compile nossa aplicação e teste, abra várias vezes o executável. Você perceberá que só é possível conectar 6 usuários.
Espero, caros leitores, que esses 3 artigos tenham dado uma idéia de como montar um aplicação multi-camadas desde o banco até o cliente de aplicação. Não se limitem ao que foi mostrado aqui, pois esse mesmo conteúdo pode ser enriquecido e muito.
Que vocês tenham excelentes projetos.
Abraços e até a próxima!
Nota:
Instância: Toda vez que é criado um novo objeto em memória.
DataSnap: Tecnologia que usamos para criar aplicações multi-camadas.
Categories: Categorias na verdade são nomes de grupos de funções. Podemos criar uma função e associá-la ao grupo. Caso o grupo não exista, ele é criado.
Ótimo artigo eu tava muito ancioso pela 3ª parte, procurei material desse tipo na net e não encontrei nada.
Se alguem tiver ou souber onde posso adquirir mais sobre esse assunto porfavor me da um alo!!
ao configurar a propriedade ServerName do SocketConnection aparece essa mensagem de erro: "nenhuma conecção pode ser feita por a maquina de destino a recusou ativamente (10061) on API".
O que pode ter acontecido???
Olá caros leitores, gostaria de enfatizar, visto que não falei nos artigos, que o firewall é um dos fatores que podem vir a atrapalhar a conexão com o servidor de aplicação, verifique no firewall do windows ou no firewall que vc usa, se a conexão com a porta 211 está liberada.
A porta 211 é a porta que o SocketServer (scktsrvr.exe) usa para conversar com a aplicação servidora.
Quaisquer dúvidas podem entrar em contato pelo e-mail, será um enorme prazer tentar ajudá-los.
Robert Gaffo
Amigo eu desabilitei o firewall do windows e até o meu anti viros avast e ainda não rolou....
faço tudo direito, coloco o ip e quando voou colocar o ServerName aparece aquela mesma mensagem porfavor me ajude o que devo fazer???
Olá caros leitores,
Tem recebido vários e-mail sobre um erro que acontece durante o desenvolvimento, a mensagem de erro é:
Windows socket error: No connection could be made because the target machine actively refused it (10061), on API 'connect'
Nenhuma conexão pode ser feita por a maquina de destino a recusou ativamente (10061), on API'connect'.
Esse erro ocorre por duas prováveis causas:
* O programa "scktsrvr.exe" que está na pasta Bin deve estar em execução, pois, esse é o programa entre a aplicação cliente e servidora.
* O firewall instalado em sua máquina está bloqueando a porta 211, que é usada para a comunicação.
Espero tê-los ajudado.
Bom desenvolvimento e estudo.
Robert Gaffo
Fiquei um tempão tentando resolver este erro de socket (10061) e mesmo seguindo todas as dicas nada resolvia. Foi ai que resolvi analizar as possibilidades menos prováveis, eu tinha desabilitado o Firewell do windows e o ZoneAlarm (um outro firewall), mas o socket não conectava, descobrir que mesmo com ZoneAlarm fechado ele continuava bloqueando a conexão, para resolver ativei novamente o ZomeAlarm e explicitamente liberei o acesso à porta 211 e... VIVA!!!, funcionou, isso pode ocorrer com outros firewell tb, boa sorte!!!
Responder comentárioParabém pela ótima colaboração, já venho estudando o assunto, mas estava complicado, passar da teoria a prática. Agora os caminhos estão iluminados.
Responder comentárioOs textos publicados neste espaço são de responsabilidade única de seus autores (colunistas e leitores) e podem não expressar necessariamente a opinião do iMasters.
Robert Gaffo é programador Delphi e instrutor de programação em Delphi e outras linguagens como Visual Basic, C/C++ e Java. Leciona aulas de conceitos de Banco de Dados, SQL Server, Oracle, Interbase/Firebird e MySql e dá treinamentos In Company. Trabalha com Delphi em aplicações desktop e multi-camadas.
2001 - iMasters FFPA Informática Ltda - Todos os direitos reservados.