Você está na página 1de 6

:: Active Delphi http://www.activedelphi.com.br/print.php?

sid=249

Sockets
Data: Monday, July 18 @ 23:44:00
Tópico Administrador

Bem, talvez você já tenha rodado bastante em busca de algo sobre sockets no Delphi, e acho que você vai gostar bastante do
conteúdo encontrado neste artigo...

Introdução
Bem, talvez você já tenha rodado bastante em busca de algo sobre sockets no Delphi, e acho que você vai gostar bastante
do conteúdo encontrado neste artigo. Falando um pouco sobre mim: Meu nome é João Nelson Lima, trabalhei com Delphi em
uma empresa de automação comercial durante 1 ano e seis meses. Mas antes já utilizava o Delphi, mas nada de forma
profissional, vamos dizer assim. Hoje tenho 22 anos e moro em Fortaleza. Sou estudante do CEFET – CE. Meu e-mail é
jnelson3@ig.com.br. E assim como você, enfrento os mesmo problemas para encontrar conteúdos avançados de Delphi. Por
isso resolvi passar meus conhecimentos para os interessados. E por favor se alguém for mudar ou publicar me comunique.
Dúvidas e sugestões são bem vindas. Por fim gostaria de desejar a você, caro leitor, uma excelente leitura e um aprendizado
útil e empolgante.

Instalando os compoentes no Delphi 7

Para isso vá no menu Component | Install Packages... Na janela que ira surgir clique no botão Add... e procure pelo arquivo
dclsockets70.bpl. De OK e pronto! Os componentes irão aparecer na palleta Internet.

Agora vamos direto ao Assunto

TserverSocket – Este componente como o nome já diz é o SERVIDOR. Ele será responsável por receber as conexões. De
quem? Dos TClientSocket! É importante perceber este conceito em que cada TclientSocket conecta a um e somente um
servidor. Sempre que você quiser fazer uma comunicação usara no mínimo um Server e um Client (Vamos passar a chamá-los
assim OK?) Um outro detalhe super importante é que no caso do servidor ele recebe um integer de conexões.
Configuração mínima:

O circulo maior representa o server e o quadrado pequeno é o cliente.


TclientSocket – Este componente como o nome já diz é o CLIENTE. É com ele que conectamos aos servidores. Pense nele
como a janela do seu browser. Com ele podemos nos conectar em qualquer servidor. Mas para isso temos que fazer alguns
ajustes que veremos a seguir. Por enquanto é importante pegar o conceito de que cada Client se liga somente e diretamente a
um Server e o Server poder receber vários Clients. De cara pode surgir a seguinte duvida: Ora, se o client está ligado no
servidor como faço para ele falar com outro client ??? Não tem saída meu caro! Sempre vai passar pelo servidor, não há
mágica, o que vai acontecer que iremos informar ao servidor o destinatário final da mensagem quando o servidor receber e
“perceber” que a mensagem deve se entregue a outro Client, ele irá enviar uma mensagem ao Client correspondente. Isso é o
protocolo de comunicação, ele é pessoal e cada um vai implementar como achar melhor.

Iniciando a comunicação

Irei primeiro explicar as conexões simples, que tem no exemplo do Delphi. Esta conexão simples serve apenas para
comunicar um cliente a um servidor e vice versa.
Neste projeto iremos construir duas aplicações, uma servidora e outra cliente, com o objetivo de fazer um Chat.
Por questões didáticas iremos começar pelo servidor que terá a medíocre missão de confirmar uma informação recebida.
Com o Delphi aperto e um novo projeto iniciado colocaremos somente o componente TServerSocket e iremos alterar as
propriedade PORT para 2255 e NAME para Servidor. Teremos:

1 de 6 17/5/2011 16:18
:: Active Delphi http://www.activedelphi.com.br/print.php?sid=249

É claro que o número da porta pode usar outro, mas por padrão adotei este aleatoriamente.
Agora vamos configurar os eventos. Primeiro os do componente depois o Form1. No componente TServerSocket que iremos
chamar de Server ou componente Servidor, iremos programar o evento OnClientRead. Este evento é acionado sempre que
chaga algo no servidor, isto é, sempre que um cliente envia algum dado.
Como já foi dito antes nossa aplicação ira apenas confirmar que recebeu algo, então iremos deixar a procedure assim:

procedure TForm1.ServidorClientRead(Sender: TObject; Socket: TCustomWinSocket);


begin
Servidor.Socket.Connections[0].SendText('Recebi algo');
end;

Isso fará com que que o servidor ao receber qualquer dado, envie uma resposta, ou seja uma string contendo “Recebi algo”
para a primeira conexão.
Para inicio precisamos agora somente ativar nosso Servidor. Então o evento OnCreate do Form deve ficar assim:

procedure TForm1.Form1Create(Sender: TObject);


begin
Servidor.Active := True;
End;

Agora vamos para o lado do Cliente. Para isso devemos iniciar uma nova aplicação. E colocaremos o componente
TclientSocket, um memo, um Button, e um edit. O arranjo dos componentes é 100% pessoal mas o meu ficou com essa cara:

2 de 6 17/5/2011 16:18
:: Active Delphi http://www.activedelphi.com.br/print.php?sid=249

Com os componentes posicionados, iremos alterar algumas propriedade básicas. De cara temos que mudar o NAME do
TClientSocket para CLIENTE e iremos atribuir o mesmo valor que foi dado a propriedade Port do servido para a do cliente isso
é 2255. e claro o Address(endereço) que vai ser o o IP, no nosso caso o 127.0.0.1 que é o de LOOPBACK, pois as duas
aplicações rodarão na mesma maquina.
Iremos programar os comando de envio e recebimento de mensagens no formato string =) com isso já conseguiremos
fazer um chat, mas somente entre as duas aplicações, para que possamos adicionar mais pessoas teremos que modificar a
maneira como o servidor vai gerenciar as conexões e isso requer mais cuidados, conceito de alocação dinâmica e ponteiros.
Que veremos mais adiante.
O Edit1 vai ser a entrada de texto que vai ser enviada o botão vai executar o procedimento para enviar e no memo
guardaremos as respostas do servidor.
Observe os códigos e veja como é simples:

Evendo OnClick do Botão:

Procedure TForm1.Button1Click(Sender: TObject);


begin
CLIENTE.Socket.SendText(Edit1.Text);
end ;

Evento onRead do TclientSocket:

procedure TForm1.ClienteRead(Sender: TObject; Socket: TCustomWinSocket);


begin
Memo1.Lines.Add(Socket.ReceiveText);
end;

E claro a ativação do servidor no onCreate do Form1:

procedure TForm1.FormCreate(Sender: TObject);


begin
CLIENTE.Open;
end;

Meu caro agora você já pode rodar as duas aplicações e ver o que acontece. Lembre-se que PRIMEIRO RODE O SERVIDOR e
depois o cliente. Fácil perceber o porque.

Indo alem

Iremos agora dar um passo a frente, vamos ver como colocar mais um cliente conectado no servidor.
Experimente rodar duas vezes o aplicativo cliente, observe que a conexão é efetivada e que você pode a partir deste segundo
cliente enviar mensagens para o servidor, mas quanto ao recebimento da resposta, todos vão para o o primeiro =/ e somente
vai para o segundo se o primeiro sair. Teste! Experimente.... e comprove

Parando pra pensar

Ficou fácil notar que aquele 0 (Zero) no comando lá em cima usado para enviar uma resposta pra o cliente se refere ao
numero da conexão destino.

Servidor.Socket.Connections[0].SendText('Recebi algo');

3 de 6 17/5/2011 16:18
:: Active Delphi http://www.activedelphi.com.br/print.php?sid=249

Isso é uma contagem direta que o servidor faz começa no 0 e vai até o limite do tipo INTEGER. Quando entra um ele passa a
ser o ZERO se entrar outro passa a ser o 1 e outro passa a ser o 2 e assim por diante, isso muda se alguém sair, é como uma
pilha quem está em cima do que saiu cai uma posição. Assim se o que tava na posição um desconectar o ZERO não se altera
mais a partir do DOIS todos caem uma posição e logo o que era 2 passa a ser o UM.
Vamos imaginar a seguinte situação, o usuário A se conectou logo então ele pegou a posição 0(zero), isso quer dizer que
sempre que enviar o comando

Servidor.Socket.Connections[0].SendText(’qualquer texto aqui dentro’);

Esse texto então só vai para o usuário A. Agora o usuário B entra e caso nos queremos enviar uma mensagem para B temos
que informar index 1 assim:

Servidor.Socket.Connections[1].SendText(’qualquer texto aqui dentro’);

Fica extremamente obvio que no caso de um usuário C entrar o index deve ser 2, logo temos uma rotina pra que o servidor
envie o que receber para todos os usuários. Isso é temos o principio de um principio de programa de chat =)

Agora toda mensagem que chegar no servidor, ao invés de ser apenas confirmada vai ser retornada a todos os usuários que a
ele estão conectados.

Iremos modificar o evento OnClientRead para que fique assim:

procedure TForm1.ServidorClientRead(Sender: TObject; Socket: TCustomWinSocket);


Var MsgRecebida : String;
I : integer;
begin

MsgRecebida := socket.ReceiveText; // Pega o conteúdo enviado

For i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
Serversocket1.Socket.Connections[i].SendText(MsgRecebida);

end;

Simples não é? Pegamos o conteúdo que foi enviado, e mandamos para todos os conectados no momento. Inclusive ao usuário
que mando a mensagem. Isso é... Fizemos um Chat. Sugiro que coloque mais um Edit na aplicação cliente para que sirva como
um campo para o Nick dos usuários e agora no evento de clique do botão ajuste para enviar o “nick” da pessoa, por exemplo:

‘<’+Edit2.text+’> ’ +edit1.text;

Muito simples =) realmente sim. O problema é que normalmente temos que enviar dados específicos para cada usuário,
sentimos essa necessidade logo que pensamos em fazer uns sistema com logon, em que se pede senha, teremos q confirmar
se o usuário está liberado ou não. Outra necessidade é quando temos que enviar mensagem em modo privado. Isso temos que
saber quem é quem nas conexões.

Entendeu isso? Se nosso gerenciador de conexões não coordenar direitinho quem cai quem ta na posição 0, 1, 2 e etc
podemos ter complicações serias. Se você tentar mandar mensagem para uma conexão que não existe certamente vai dar pau
e se você não coordenar estas conexões de forma eficiente provavelmente uma mensagem que ia pra FULANO pode ira pra o
BELTRANO.

Entendido esta etapa temos que somente agora aprender a como gerenciar isso. Vamos então criar um GC ou seja o
gerenciador de conexões.

O Primeiro passo é saber como vamos organizar as conexões. A idéia base é gerar é identificar cada conexão com um código
e armazenar em uma estrutura igual a pilha de conexões do componente assim sendo quando algum cliente conectar
adicionaremos a nossa estrutura o código da conexão, quando sair deletamos, caso queiramos enviar uma mensagem
particular procuramos em nossa estrutura identificamos a posição, e enviaremos =)

Iniciando o gerenciador de conexões

Analisamos o que o Delphi nos trás, encontrei o TList que é uma estrutura pronta para gerenciar ponteiros em pilha. Para gerar
os códigos iremos usar ponteiros até porque é a forma de identificarmos os usuários quando conectam, desconectam ou
enviam mensagens. Através da propriedade DATA.

Declarei a variável

IDConexoes : TList;

4 de 6 17/5/2011 16:18
:: Active Delphi http://www.activedelphi.com.br/print.php?sid=249

No evento onCreate do form principal criei o IDConexoes assim:

IDConexoes := TList.Create;
IDConexoes.Clear;

No evento OnClose do form principal liberei ele da memória assim:

IDConexoes.Free;

Agora vamos a parte que requer mais atenção, iremos programar o evento On ClientConnect e o OnClientDisconnect.

Primeiro a conexão do cliente:

procedure TForm1.ServidorClientConnect(Sender: TObject; Socket: TCustomWinSocket);


Var IDsocket : ^byte;
begin
New(IDSocket);
Socket.Data := IDSocket;
IDConexoes.Add(Socket.data);
end;

O que fiz foi simplificar ao máximo. Criei uma variável local como ponteiro, reservei um ponteiro novo para a conexão informei
que o ponteiro pertence a ela e adicionei o endereço na nossa lista.

Agora o procedimento de desconexão

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;


Socket: TCustomWinSocket);
Var NumConex : integer;
Begin
IDConexoes.Remove(Socket.Data);
Dispose(Socket.Data);
end;

Percebeu como esse TList é show? Ele faz tudo sozinho!

Como localizar o cliente....

Para finalizar vamos ver como responder somente para o cliente que enviou a mensagem. Por exemplo, suponhamos que
estejam conectados os usuários A, B e C, mas não sabemos quem está em qual posição. Mas está registrado as entradas no
nosso TList (IDConexoes). E temos que enviar uma mensagem resposta para o cliente B como. Vamos admitir que sempre que
ele escrever ‘HORAS?’ vamos enviar uma string com a hora atual. Ok? A pergunta que teima em pairar no ar é “Como saber o
INDEX dele?” Para responder temos que voltar para o evento onClientRead, mas e antes iremos criar a função LocalizaCliente,
assim:

Function TForm1.LocalizaCliente(Cli : Pointer):Integer;


Begin
Result := IDConexoes.IndexOf(Cli);
End;

Agora sim vamos ao evento :

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;


Socket: TCustomWinSocket);
Var Msg : String;
IDCli : integer;
HoraStr : String;
begin
Msg := socket.ReceiveText;
If Msg = ‘HORA?’ then
Begin
IDCli := LocalizaCliente(Socket.Data);
HoraStr := FormatDateTime('HH:mm:ss',Now);

5 de 6 17/5/2011 16:18
:: Active Delphi http://www.activedelphi.com.br/print.php?sid=249

If (IDCli >= 0) then


Servidor.Socket.Connections[IDCli].SendText(HoraStr);
end;
end;

Moleza não? Espero que tenha ficado tudo claro.Esse assunto é muito extenso. Espero que tenha esclarecido algo. Qualquer
coisa podem me encontrar por e-mail e no MSN Menssager também. Até +, forte abraço e tudo de bom,

Nelson Lima - Diretor Geral.


NeoSoft - “Seu futuro é o nosso presente”

Digitado por :: Active Delphi


http://www.activedelphi.com.br/

A URL para esta notícia é:


http://www.activedelphi.com.br/modules.php?op=modload&name=News&file=article&sid=249

6 de 6 17/5/2011 16:18

Você também pode gostar