Clique para saber mais...
  Home     Download     Produtos / Cursos     Revista     Vídeo Aulas     Fórum     Contato   Clique aqui para logar | 12 de Junho de 2026
  Login

Codinome
Senha
Salvar informações

 Esqueci minha senha
 Novo Cadastro

  Usuários
168 Usuários Online

  Revista ActiveDelphi
 Assine Já!
 Edições
 Sobre a Revista

  Conteúdo
 Apostilas
 Artigos
 Componentes
 Dicas
 News
 Programas / Exemplos
 Vídeo Aulas

  Serviços
 Active News
 Fórum
 Produtos / Cursos

  Outros
 Colunistas
 Contato
 Top 10

  Publicidade

  [Artigos]  Sockets
Publicado por ActiveDelphi : Segunda, Julho 18, 2005 - 11:44 GMT-3 (42442 leituras)
Comentários 34 Comentários   Enviar esta notícia a um amigo Enviar para um amigo   Versão para Impressão Versão para impressão
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:


 

     É 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:
 

     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');

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;


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);
     
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”
 



Comentários Comentários
   Ordem:  
Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos.


por: VirtualC : Jul 19, 2005 - 09:05
(Informações sobre o membro | Enviar uma mensagem) http://
Parabens Nelson pelo seu artigo foi um dos melhores que ja li!!!! Ficou bem simples e objetivo... Muito Bom mesmo.


por: rpessoa : Ago 02, 2005 - 11:22
(Informações sobre o membro | Enviar uma mensagem)
eu só não entendi essa parte :
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;


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;

Aonde declarar ? Aonde colocar ?

desde já obrigado !!!


por: noobsaibot : Ago 22, 2005 - 02:21
(Informações sobre o membro | Enviar uma mensagem)
Caro Nelson,

Gostaria de saber se você pode mostrar como ficaram no final do processo os fontes do SERVIDOR e do CLIENTE, pois, implementei aqui e não está enviando as mensagens e/ou se está não está exibindo para os clientes.

Outra coisa, a "Var NumConex : integer; " do trecho abaixo foi criado com qual finalidade?

"procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
Var NumConex : integer;
Begin
IDConexoes.Remove(Socket.Data);
Dispose(Socket.Data);
end; "

O artigo está muito bom,

Aguardo ser retorno.


por: an.der.son (anderson.ol@gmail.com) : Nov 25, 2005 - 11:50
(Informações sobre o membro | Enviar uma mensagem) http://www.and3rson.rg3.net
Pow kra... show o seu artigo... jah usava Sockets em D6, mas fiquei indignado qdo fiz um update para D7, pois sempre ouvi dizer q a borland nunca remove componentes, pois a Borland mantem para efeito de compatibilidade....
Show... perfeito seu artigo
Parabens.


por: gsoft : Jan 04, 2006 - 11:18
(Informações sobre o membro | Enviar uma mensagem)
Minha dúvida é a seguinte, em Adrees, ao invés de IP eu posso colocar o NOME do servidor e funciona também?


por: Aline_Carolzinha : Jan 12, 2006 - 12:44
(Informações sobre o membro | Enviar uma mensagem)
ADOREI SEU ARTIGO, ESTAVA TODA ENROLADA NESSE ASSUNTO, COM ESSA SIMPLES E ÚTIL EXPLICAÇÃO CONSEGUI ENTENDER SOBRE O ASSUNTO.


por: yoshinori : Mai 01, 2006 - 09:22
(Informações sobre o membro | Enviar uma mensagem)
Alguem conseguiu fazer esta parte:
Function TForm1.LocalizaCliente(Cli : Pointer):Integer;
Begin
Result := IDConexoes.IndexOf(Cli);
End;

Essa parte eu naum consigo implementar não sei aonde eu coloco ??? Por favor prescizo terminar isso urgente... Agradeço


por: jairconde : Mai 23, 2006 - 03:03
(Informações sobre o membro | Enviar uma mensagem) http://http://
Li seu artigo, não testei nada, mas já posso adiantar que é realmente um grande show de bola mesmo.
Parabens a você Nelson!


por: o_bob_esponja_o : Out 09, 2006 - 03:06
(Informações sobre o membro | Enviar uma mensagem) http://
kra muito massa + vc poderia poderia me dar uma dica de como eu poderia fazer uma converça privada com algum nick em especifico?


por: Borghal : Dez 05, 2006 - 05:59
(Informações sobre o membro | Enviar uma mensagem) http://http://
Nelson, essa tua dica é muito boa cara... boa mesmo, com ela eu conseguir fazer um programinha basico pra eu e meus amigos brincarmos de rpg de mesa pela net... bom se alguem quizer o programa, divirtam-se:

http://br.geocities.com/sincos_pcbs/

Grato
Paulo


por: macks : Nov 09, 2007 - 06:31
(Informações sobre o membro | Enviar uma mensagem)
Cara aki copilo blz so q quando vo executa da um erro access violation at adress 00403f09 in module 'batepapo.exe'. read of address 00000000. sabe o q pode ser?


por: DavidsonDFGL (joaquimgtx@yahoo.com.br) : Abr 25, 2009 - 10:52
(Informações sobre o membro | Enviar uma mensagem)
Nelson, você está de parabéns, o melhor artigo que ja vi até hoje, muito bem explicado, tirou muitas duvidas minhas em relação a sockets, muito bom, :) .


por: nathanpc (nathanpc@ymail.com) : Mai 06, 2009 - 06:06
(Informações sobre o membro | Enviar uma mensagem) http://
Olá,
Alguem poderia me falar se é possível criar este servidor e o cliente para que os meus amigos, lembrando que o meu ip é dinamico, mas eu posso usar o no-ip que eu tenho, por favor me ajudem.

Obrigado,
Nathan Paulino Campos


por: neidl (neidantaslopez@gmail.com) : Nov 13, 2009 - 02:53
(Informações sobre o membro | Enviar uma mensagem) http://
Fiz:

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

Mas continua enviando o texto apenas em uma janela... o que será que eu errei?


por: Bechir (bechirbitar@hotmail.com) : Nov 27, 2009 - 04:15
(Informações sobre o membro | Enviar uma mensagem) http://http://
Meu esteu artigo é muito show estava atraz de exemplos para usar Sockets mais nunca encontrei nada com tanta clareza nas explicações mais para ficar Show mesmo teria que ter mais 2 coisinhas que seria derrubar um usuário inconveniente e desligar remotamente um monitor da rede isto é possivel ?

Parabens.


por: benkoms (thiagobenko@hotmail.com) : Out 02, 2012 - 11:27
(Informações sobre o membro | Enviar uma mensagem)
Primeiramente gostaria de parabeniza-lo pelo artigo, sem dúvidas está ajudando muita gente (eu me incluo na lista).
Aproveitando da boa vontade dos colegas, eu fiz um aplicativo, não de chat, mas me auxiliar em monitoramento de redes, a questão é:
Teria como eu fazer tipo um scanner, onde eu verificasse se o meu aplicativo está rodando na máquina, se tiver ele me confirma e acrescenta o ip a uma listbox ou coisa assim.

Imaginem vcs uma empresa com 30 computadores vc ter que ficar testando um por um para ver se está rodando ou não.

Quem puder ajudar, me mande um e-mail: thiago@concepttecnologia.com
  Edição 112

Revista ActiveDelphi

  50 Programas Fontes


  Produtos

Conheça Nossos Produtos

Copyright© 2001-2016 – Active Delphi – Todos os direitos reservados