Social Icons

^^

terça-feira, 29 de março de 2011

COMPLETO Chat com sockets um pouco diferente do que costumamos ver...

Bem galera, essa é minha primeira postagem, o chat que postarei o desenvolvimento aqui é dividido em 2 partes : servidor e cliente, como já se esperava!!!

Na parte do servidor será configurada a porta que o chat usará e também passam por ele todas as mensagens enviadas pela outra parte do programa, a cliente.

O servidor gerenciará todas as mensagens, quem entra e quem sai do chat e pode kickar,desconectando o cliente e até banir, que reiniciará a aplicação,oque é bastante chato!...isso quer dizer que quem for "persona non grata" a qualquer momento pode ser retirado do chat.

O cliente tem apenas a função de conectar a um servidor já existente após ser identificado por usuário e senha.Há a opção de mandar mensagens no "GERAL" como também podemos enviar mensagens direcionadas a apenas um usuário....agora chega de bla bla bla e vamos finalmente iniciar o projeto.

O projeto está finalizado, e achei mais conveniente postar aqui a versão sem banco de dados..pois ia complicar demais.O que postarei agora é totalmente funcional apenas não tem o banco de dados.

Vamos La:

Crie uma pasta com o nome chat e dentro dessa pasta crie duas pastas: cliente e servidor.

Começaremos pelo Servidor da aplicação.

Abre o Delphi, crie um form, eu chamei aqui de frmServidor.

Salve tudo na pasta chat dentro da subpasta servidor com o nome que você quiser!

Insira os seguintes componentes:

1 groupbox com o nome de gbUsers e caption Usuários conectados.Dentro dele ponha um listview com o nome de LV, adicione as seguintes colunas nesse LV:

ID,Nick,rede local,internet e hostname.

Ponha dois panels, um com o nome de pnlNick e outro com o nome de pnlAtual.

1 groupbox com o nome de gbMsgs com caption Mensagens e dentro dele um memo com o nome memoMsgs e propriedade align=AlClient.

1 groupbox com o nome de gbMsg com caption Enviar mensagem e dentro dele um memo com o nome de memoMsg e a propriedade scrollbars=ssVertical e um checkbox com o nome de cboxPVT.

1 groupbox com o nome gbCfg com caption Opções do servidor e dentro dele um LabeledEdit com o nome edtPorta e labeledcaption=Porta e também um bitbtn com o nome de btnIniciaServidor e caption=Iniciar Servidor.

1 groupbox com o nome de gbStatus com caption=Status e dentro dele um memo com nome de memoStatus e a propriedade align=AlClient.

1 popupmenu com o nome de PopupUsers com dois itens: kickar e banir.

1 ClientSocket com o nome de Cliente

1 ServerSocket com o nome de Servidor

Seu formulário deve ficar parecido com isso aqui :

Agora na propriedade popupmenu do LV selecione PopupUsers.

Codificando:

Declare a variável publica:

id_conexao_usuario : integer;

O clique do botão IniciarServidor criei uma procedure para reduzir os códigos...

procedure TfrmServidor.AtivarDesativarServer;

var

i : integer;

begin

if servidor.Active=true then

begin

for i:=0 to servidor.socket.activeconnections-1 do

servidor.Socket.connections[i].SendText('##SERVIDOR_DESLIGADO##AVISO: O servidor foi desligado.');

servidor.Active:=false;

cliente.Active:=false;

btnIniciarServidor.Caption:='Iniciar Servidor';

frmServidor.Caption:='Chat ::ProgMaster:: (Servidor) - Status do servidor: INATIVO - por Marcísio Souza';

edtPorta.ReadOnly:=false;

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

lv.Clear;

memoMsgs.Lines.Add('Servidor parado em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.lines.Add('Volte sempre '+pnlNick.caption);

memoStatus.Lines.Add('Servidor inativo.');

end

else

begin

servidor.Port:=strtoint(edtPorta.Text);

servidor.Active:=true;

cliente.Host:=GETIP;//funçao para pegar o ip da maquina

cliente.Port:=servidor.Port;

cliente.Active:=true;

edtPorta.ReadOnly:=true;

btnIniciarServidor.Caption:='Parar Servidor';

frmServidor.Caption:='Chat ::ProgMaster::(Servidor) - Status do servidor: servidor ATIVO na porta '+inttostr(servidor.Port)+' em ('+GETIP+') - por Marcísio Souza';

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

memoMsgs.Clear;

memoStatus.Clear;

memoMsgs.Lines.Add('Servidor iniciado em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.lines.Add('Bem-vindo '+pnlNick.caption);

memoStatus.Lines.Add('Servidor ativo.');

end;

end;

adicione também essas funções, GETIP e Retorna_IP_Internet.

function TfrmServidor.GetIP:string;

var //Uses Winsock

WSAData: TWSAData;

HostEnt: PHostEnt;

Name:string;

begin

WSAStartup(2, WSAData);

SetLength(Name, 255);

Gethostname(PChar(Name), 255);

SetLength(Name, StrLen(PChar(Name)));

HostEnt := gethostbyname(PChar(Name));

with HostEnt^ do

begin

Result := Format('%d.%d.%d.%d',

[Byte(h_addr^[0]),Byte(h_addr^[1]),

Byte(h_addr^[2]),Byte(h_addr^[3])]);

end;

WSACleanup;

end;

Function Retorna_IP_Internet : String;

var //Colocar em USES Idhttp

txt :string ;

http : tidhttp ;

begin

http := tIdhttp.Create(nil) ;

try

Try

txt:=http.Get('http://www.whatismyip.com/automation/n09230945.asp');

except

exit;

end;

finally

http.Free ;

result := txt ;

end;

END;

Importante: você deve acrescentar em uses IdHttp e Winsock e também acima da palavra reservada PRIVATE declarar a procedure AtivarDesativarServidor e a function GETIP.

procedure AtivarDesativarServer;

function GetIP : String;

Codificando o btnIniciarServidor:

if edtPorta.Text<>''then //verifica se não esta vazio o edtPorta

begin

AtivarDesativarServer; //entra na procedure AtivarDesativarServer

memoMsg.SetFocus; //Poe o foco no memoMsg

end

else //se estiver vazio...

begin

application.MessageBox('A porta do servidor está em branco','Não permitido',mb_iconwarning); //exibe a mensagem

edtPorta.SetFocus; //poe o foco no edtPorta

exit;

end;

item do menu popup Kickar:

procedure TfrmServidor.KickarClick(Sender: TObject);

var

motivo : string; // variavel do tipo string

begin

if id_conexao_usuario=-1 then // se a variavel for -1 sai da rotina

exit;

if ansicomparetext(pnlAtual.Caption,pnlNick.Caption)=0 then

begin //se tentar kickar o administrador ...

application.MessageBox('Impossível derrubar a conexão do Servidor','Kick negado!',mb_iconinformation); //exibe mensagem

exit; //sai da rotina

end;

motivo:=inputbox('Kickando usuário','Digite o motivo',''); //a variável recebe o valor digitado

if motivo='' then //if motivo for vazio ..

motivo:='Motivo não especificado'; //motivo recebe uma frase padrao

servidor.Socket.Connections[id_conexao_usuario].SendText('##KICK##'+motivo); //envia para o usuario selecionao a msg q eh interpretada como kick! Depois explico os protocolos que utilizei

item do menu popup Banir: //eh a mesma explicação do kickar :p

procedure TfrmServidor.BanirClick(Sender: TObject);

var

motivo : string;

begin

if id_conexao_usuario=-1 then

exit;

if ansicomparetext(pnlAtual.Caption,pnlNick.Caption)=0 then

begin

application.MessageBox('Impossível derrubar a conexão do Servidor','Ban negado!',mb_iconinformation);

exit;

end;

motivo:=inputbox('Banindo usuário','Digite o motivo','');

if motivo='' then

motivo:='Motivo não especificado';

servidor.Socket.Connections[id_conexao_usuario].SendText('##BAN##'+motivo);

end;

evento onclick do LV:

procedure TfrmServidor.LVClick(Sender: TObject);

begin

if lv.ItemIndex=-1 then //se nenhum item for clicado entao sai da rotina

exit;

cboxPVT.Checked:=true; //marca o cboxPVT

cboxPVT.enabled:=true; //ativar o cboxPVT

pnlAtual.Caption:=lv.Selected.SubItems.Strings[0];//atribui ao caption do pnlAtual o valor do subitem nick do usuario selecionado

id_conexao_usuario:=lv.ItemIndex;//a variável recebe o valor do índex do usuário selecionado

memoMsg.SetFocus;//Poe o foco no memoMsg

exit; //sai da rotina

end;

Evento onread do Servidor:

procedure TfrmServidor.ServidorClientRead(Sender: TObject;

Socket: TCustomWinSocket);

var

textorecebido : string;

Nick,Nick2,IP_NET,IDSOCKET,lista_user : String;

L : TListItem;

I, usuario_pvt : integer;

begin

textorecebido := Socket.ReceiveText;

usuario_pvt:=-1;

FlashWindow(Application.Handle, True);//faz a janela na barra de tarefas piscar

//checa se é uma conexao nova no chat e envia a lista de usuarios presentes

if ((pos('##NICK##',textorecebido)<>0) and (pos('##QUERO_LISTA##',textorecebido)<>0)) then

begin

delete(textorecebido, pos('##QUERO_LISTA##',textorecebido), length(textorecebido));

nick:=(copy (textorecebido,(pos('##NICK##',textorecebido)+length('##NICK##')) ,

pos('//',textorecebido)-(pos('##NICK##',textorecebido)+length('##NICK##'))));

ip_net:=copy(textorecebido, pos('//',textorecebido)+length('//'), length(textorecebido));

L:=lv.items.add;

L.Caption:=inttostr(socket.Handle);

L.SubItems.Add(nick);

L.SubItems.Add(socket.RemoteAddress);

L.SubItems.Add(ip_net);

L.SubItems.Add(socket.RemoteHost);

nick2:=nick;

//enviando lista de usuarios para todos os clientes

for i:=0 to servidor.Socket.ActiveConnections-1 do

begin

idsocket:=lv.Items[i].Caption;

nick:=lv.Items[i].SubItems.Strings[0];

lista_user:=lista_user+'-_-_-'+IDSOCKET+'//\\'+NICK;

end;

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.socket.Connections[i].SendText('##LISTA_USUARIOS##'+lista_user+'$:$:'+'O nick '+nick2+' (no IP '+socket.RemoteAddress+') entrou na sala');

exit;

end;

//////////////////////////////////////////////////////////////////////////////////////

//mensagem para todos///////////////////////////////////////////////////////

if pos('##MSG##',textorecebido)<>0 then

begin

textorecebido:=copy(textorecebido, pos('##MSG##',textorecebido)+length('##MSG##'), length(textorecebido));

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.socket.Connections[i].SendText(textorecebido);

memoMsgs.Lines.Add(textorecebido);

exit;

end;

/////////////////////////////////////////////////////////////////////////////////////

//mensagem privada///////////////////////////////////////////////////////////////////

if pos('##MSGPVT##',textorecebido)<>0 then

begin

usuario_pvt:=StrToInt( copy( textorecebido, pos('#*',textorecebido)+length('#*'), pos('*#',textorecebido) - (pos('#*',textorecebido)+length('#*')) ));

delete(textorecebido, pos('::nick2::',textorecebido),length('::nick2::') );

delete(textorecebido, pos('::/nick2::',textorecebido),length('::/nick2::') );

textorecebido:=copy( textorecebido, pos('*#',textorecebido)+length('*#'), length(textorecebido) );

servidor.Socket.Connections[usuario_pvt].SendText(textorecebido);

memoMsgs.Lines.Add(textorecebido);

exit;

end;

/////////////////////////////////////////////////////////////////////////////////////

end;

esse evento acima é o mais complicado, pois e ele que vai interpretar todas as msgs que entram e saem do chat.é bom vocês lerem bem porque ta intuitivo..o trabalho difícil eu já tive rsrs.reparem que eh tudo com base nas funções copy, delete e pos, referentes à manipulação de strings.

Evento onshow do frmServidor

procedure TfrmServidor.FormShow(Sender: TObject);

begin

frmServidor.Caption:='Chat ::ProgMaster:: (Servidor) - Status do servidor: INATIVO - por Marcísio Souza';

id_conexao_usuario:=-1; //seta a variavel para -1

cboxPVT.enabled:=false; //desativa o cboxpvt

cboxPVT.checked:=false;//desmarca o cboxpvt

edtPorta.ReadOnly:=false; //poe como somente leitura o edtPorta

pnlAtual.Caption:='Todos'; //define o caption do pnlAtual para Todos

end;

evento onclose do frmServidor:

procedure TfrmServidor.FormClose(Sender: TObject;

var Action: TCloseAction);

var

i : integer;

begin

if servidor.Active=true then //se o servidor estiver ativo..

for i:=0 to servidor.socket.activeconnections-1 do

servidor.Socket.connections[i].SendText('##SERVIDOR_DESLIGADO##AVISO: O servidor foi fechado.'); //envia uma msg de aviso para TODOS os clientes conectados, informando o fechamento do servidor

Servidor.Active:=false;//desativa o servidor

application.Terminate;//finaliza a aplicação

end;

evento onclick do cboxPVT:

procedure TfrmServidor.cboxPVTClick(Sender: TObject);

begin

cboxPVT.enabled:=false;//desativa o cboxPVT

pnlAtual.Caption:='Todos';//define o caption do pnlAtual para Todos

id_conexao_usuario:=-1;//seta a variável para -1

memoMsg.SetFocus;//Poe o foco no memoMsg

end;

evento onconnect do cliente:

procedure TfrmServidor.ClienteConnect(Sender: TObject;

Socket: TCustomWinSocket);

var

ip_internet : string;

begin

if retorna_ip_internet<>'' then //se a funçao NÃO retornar vazio entao

ip_internet:=retorna_ip_internet //a variavel recebe o ip da internet!

Else//senaooooooooo

ip_internet:='Sem Conexão'; // a variável recebe Sem Conexão

socket.SendText('##NICK##'+pnlNick.Caption+'//'+ip_internet+'##QUERO_LISTA##'); //envia para o cliente a mensagem com protocolo de comunicação o Nick e o ip da internet

end;

evento onclientdisconnect do Servidor:

procedure TfrmServidor.ServidorClientDisconnect(Sender: TObject;

Socket: TCustomWinSocket);

var

L : TListItem;

i : integer;

begin

L:=lv.FindCaption(0,inttostr(socket.Handle),false,true,false);

//atribui a propriedade findcaption do listview o valor do socket que desconectou…

if L<>nil then //se esse socket estiver na LV entao..

L.Delete;//remove o usuario com o socket buscado…

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.Socket.Connections[i].SendText('##DESCONECTOU##'+inttostr(socket.Handle));//envia para todos que o socket desconectou..

memoStatus.Lines.Add('Usuário desconectado: '+ Socket.RemoteAddress);//insere no memoStatus

end;

evento onclienterror do Servidor: //a mesma coisa do evento acima....:p

procedure TfrmServidor.ServidorClientError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

var

L : TListItem;

i : integer;

begin

errorcode:=0;

L:=lv.FindCaption(0,inttostr(socket.Handle),false,true,false);

if L<>nil then

L.Delete;

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.Socket.Connections[i].SendText('##ERRO##'+inttostr(socket.Handle)+'//'+pnlNick.Caption);

memoStatus.Lines.Add('Usuário desconectado por erro: '+ Socket.RemoteAddress);

end;

evento onread do Cliente:

procedure TfrmServidor.ClienteRead(Sender: TObject;

Socket: TCustomWinSocket);

var

textorecebido: string;

begin

textorecebido:=socket.ReceiveText;//a variável recebe a mensagem recebida pelo socket

if ( (pos('##LISTA_USUARIOS##',textorecebido)<>0) and (pos('$:$:',textorecebido)<>0) ) then

begin

textorecebido:=copy(textorecebido , pos('$:$:',textorecebido)+length('$:$:'),length(textorecebido));

memoStatus.Lines.Add(textorecebido);

FlashWindow(Application.Handle, True);//faz a janela na barra de tarefas piscar

exit;

end;

end;

evento onerror do Cliente:

procedure TfrmServidor.ClienteError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

begin

errorcode:=0;// com isso eliminamos aqueles erros enjoados!!

end;

evento onkeypress do memoMsg :

procedure TfrmServidor.memoMsgKeyPress(Sender: TObject; var Key: Char);

begin

if ( (key=#13) and (trim(memoMsg.Text)='') or (cliente.Active=false) ) then

//verifica se a tecla é enter e o memoMsg é diferente é vazio e se o Cliente não está ativo..se tudo estiver assim então..:

key:=#0; //nao escreve nada!

if ( (key=#13) and (key=#17) ) then //se houver a combinação de teclas control+enter entao …

memoMsg.Lines.Add(#13);//pula uma linha no memoCfg

if ( (key=#13) and (trim(memoMsg.Text)<>'') and (cliente.Active=true) ) then

begin //se tecla for enter, memoMsg nao for vazio e cliente estiver conectado..

if ( (cboxPVT.Checked=false) and (id_conexao_usuario=-1) ) then

Begin//verifica se é mensagem para todos ..se for:

cliente.Socket.SendText('##MSG##'+pnlNICK.caption+' fala para TODOS: '+memoMSG.Text);//o socket envia a um texto com protocolo, Nick e a mensagem.

memoMsg.Clear;//limpa o memoMsg

end;

if ( (cboxPVT.Checked=true) and (id_conexao_usuario<>-1) ) then//msg particular (pvt)

begin// verifica se é msg particular

cliente.Socket.SendText('##MSGPVT##'+'#*'+inttostr(id_conexao_usuario)+'*#'+ pnlNICK.caption+' fala (em PVT) para ::nick2::'+pnlAtual.Caption+'::/nick2::: '+memoMSG.Text);

//envia um texto com o nick que escreveu, o nick q vai receber, o index do nick q vai receber e a mensagem em si.

memoMsg.Clear;//limpa o memoMsg

end;

key:=#0; //naoescreve nada

end

else

exit;//sai da rotina

end;

agora é so compilar tudo e aguardar o cliente.

Código completo:

ps: ha tres eventos que nao listei pq sao apenas supérfluos...voces o verao no codigo completo

unit UnitServidor;


interface


uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, Menus, ScktComp, ExtCtrls, ComCtrls, StdCtrls, Buttons, Winsock, Idhttp;


type

TfrmServidor = class(TForm)

gbMsgs: TGroupBox;

memoMsgs: TMemo;

btnLimparMsgs: TBitBtn;

gbMsg: TGroupBox;

cboxPVT: TCheckBox;

memoMsg: TMemo;

gbCfg: TGroupBox;

btnIniciarServidor: TBitBtn;

edtPorta: TLabeledEdit;

gbUsers: TGroupBox;

LV: TListView;

pnlNick: TPanel;

pnlAtual: TPanel;

gbStatus: TGroupBox;

MemoStatus: TMemo;

btnLimparStatus: TBitBtn;

Cliente: TClientSocket;

Servidor: TServerSocket;

PopupUsers: TPopupMenu;

Kickar: TMenuItem;

Banir: TMenuItem;

Panel1: TPanel;

procedure AtivarDesativarServer;

function GetIP : String;

procedure btnIniciarServidorClick(Sender: TObject);

procedure KickarClick(Sender: TObject);

procedure LVClick(Sender: TObject);

procedure ServidorClientRead(Sender: TObject;

Socket: TCustomWinSocket);

procedure btnLimparMsgsClick(Sender: TObject);

procedure btnLimparStatusClick(Sender: TObject);

procedure FormShow(Sender: TObject);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure LVCustomDrawItem(Sender: TCustomListView; Item: TListItem;

State: TCustomDrawState; var DefaultDraw: Boolean);

procedure cboxPVTClick(Sender: TObject);

procedure ClienteConnect(Sender: TObject; Socket: TCustomWinSocket);

procedure ServidorClientDisconnect(Sender: TObject;

Socket: TCustomWinSocket);

procedure ServidorClientError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

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

procedure ClienteError(Sender: TObject; Socket: TCustomWinSocket;

ErrorEvent: TErrorEvent; var ErrorCode: Integer);

procedure memoMsgKeyPress(Sender: TObject; var Key: Char);

procedure BanirClick(Sender: TObject);

private

{ Private declarations }

public

id_conexao_usuario : integer;

{ Public declarations }

end;


var

frmServidor: TfrmServidor;


implementation


{$R *.dfm}


function TfrmServidor.GetIP:string;

var //Uses Winsock

WSAData: TWSAData;

HostEnt: PHostEnt;

Name:string;

begin

WSAStartup(2, WSAData);

SetLength(Name, 255);

Gethostname(PChar(Name), 255);

SetLength(Name, StrLen(PChar(Name)));

HostEnt := gethostbyname(PChar(Name));

with HostEnt^ do

begin

Result := Format('%d.%d.%d.%d',

[Byte(h_addr^[0]),Byte(h_addr^[1]),

Byte(h_addr^[2]),Byte(h_addr^[3])]);

end;

WSACleanup;

end;


procedure TfrmServidor.AtivarDesativarServer;

var

i : integer;

begin

if servidor.Active=true then

begin

for i:=0 to servidor.socket.activeconnections-1 do

servidor.Socket.connections[i].SendText('##SERVIDOR_DESLIGADO##AVISO: O servidor foi desligado.');


servidor.Active:=false;

cliente.Active:=false;

btnIniciarServidor.Caption:='Iniciar Servidor';

frmServidor.Caption:='Chat ::ProgMaster:: (Servidor) - Status do servidor: INATIVO - por Marcísio Souza';

edtPorta.ReadOnly:=false;

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

lv.Clear;

memoMsgs.Lines.Add('Servidor parado em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.lines.Add('Volte sempre '+pnlNick.caption);

memoStatus.Lines.Add('Servidor inativo.');

end

else

begin

servidor.Port:=strtoint(edtPorta.Text);

servidor.Active:=true;

cliente.Host:=GETIP;//funçao para pegar o ip da maquina

cliente.Port:=servidor.Port;

cliente.Active:=true;

edtPorta.ReadOnly:=true;

btnIniciarServidor.Caption:='Parar Servidor';

frmServidor.Caption:='Chat ::ProgMaster::(Servidor) - Status do servidor: servidor ATIVO na porta '+inttostr(servidor.Port)+' em ('+GETIP+') - por Marcísio Souza';

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

memoMsgs.Clear;

memoStatus.Clear;

memoMsgs.Lines.Add('Servidor iniciado em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.lines.Add('Bem-vindo '+pnlNick.caption);

memoStatus.Lines.Add('Servidor ativo.');

end;

end;


Function Retorna_IP_Internet : String;

var //Colocar em USES Idhttp

txt :string ;

http : tidhttp ;

begin

http := tIdhttp.Create(nil) ;

try

Try

txt:=http.Get('http://www.whatismyip.com/automation/n09230945.asp');

except

exit;

end;

finally

http.Free ;

result := txt ;

end;

END;


procedure TfrmServidor.btnIniciarServidorClick(Sender: TObject);

begin

if edtPorta.Text<>''then

begin

AtivarDesativarServer;

memoMsg.SetFocus;

end

else

begin

application.MessageBox('A porta do servidor está em branco','Não permitido',mb_iconwarning);

edtPorta.SetFocus;

exit;

end;

end;


procedure TfrmServidor.KickarClick(Sender: TObject);

var

motivo : string;

begin

if id_conexao_usuario=-1 then

exit;


if ansicomparetext(pnlAtual.Caption,pnlNick.Caption)=0 then

begin

application.MessageBox('Impossível derrubar a conexão do Servidor','Kick negado!',mb_iconinformation);

exit;

end;


motivo:=inputbox('Kickando usuário','Digite o motivo','');

if motivo='' then

motivo:='Motivo não especificado';

servidor.Socket.Connections[id_conexao_usuario].SendText('##KICK##'+motivo);

end;


procedure TfrmServidor.BanirClick(Sender: TObject);

var

motivo : string;

begin

if id_conexao_usuario=-1 then

exit;


if ansicomparetext(pnlAtual.Caption,pnlNick.Caption)=0 then

begin

application.MessageBox('Impossível derrubar a conexão do Servidor','Ban negado!',mb_iconinformation);

exit;

end;


motivo:=inputbox('Banindo usuário','Digite o motivo','');

if motivo='' then

motivo:='Motivo não especificado';

servidor.Socket.Connections[id_conexao_usuario].SendText('##BAN##'+motivo);

end;


procedure TfrmServidor.LVClick(Sender: TObject);

begin


if lv.ItemIndex=-1 then

exit;


cboxPVT.Checked:=true;

cboxPVT.enabled:=true;

pnlAtual.Caption:=lv.Selected.SubItems.Strings[0];

id_conexao_usuario:=lv.ItemIndex;

memoMsg.SetFocus;

exit;

end;


procedure TfrmServidor.ServidorClientRead(Sender: TObject;

Socket: TCustomWinSocket);

var

textorecebido : string;

Nick,Nick2,IP_NET,IDSOCKET,lista_user : String;

L : TListItem;

I, usuario_pvt : integer;

begin

textorecebido := Socket.ReceiveText;

usuario_pvt:=-1;

FlashWindow(Application.Handle, True);//faz a janela na barra de tarefas piscar


//checa se é uma conexao nova no chat e envia a lista de usuarios presentes

if ((pos('##NICK##',textorecebido)<>0) and (pos('##QUERO_LISTA##',textorecebido)<>0)) then

begin

delete(textorecebido, pos('##QUERO_LISTA##',textorecebido), length(textorecebido));


nick:=(copy (textorecebido,(pos('##NICK##',textorecebido)+length('##NICK##')) ,

pos('//',textorecebido)-(pos('##NICK##',textorecebido)+length('##NICK##'))));


ip_net:=copy(textorecebido, pos('//',textorecebido)+length('//'), length(textorecebido));


L:=lv.items.add;

L.Caption:=inttostr(socket.Handle);

L.SubItems.Add(nick);

L.SubItems.Add(socket.RemoteAddress);

L.SubItems.Add(ip_net);

L.SubItems.Add(socket.RemoteHost);


nick2:=nick;


//enviando lista de usuarios para todos os clientes

for i:=0 to servidor.Socket.ActiveConnections-1 do

begin

idsocket:=lv.Items[i].Caption;

nick:=lv.Items[i].SubItems.Strings[0];

lista_user:=lista_user+'-_-_-'+IDSOCKET+'//\\'+NICK;

end;

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.socket.Connections[i].SendText('##LISTA_USUARIOS##'+lista_user+'$:$:'+'O nick '+nick2+' (no IP '+socket.RemoteAddress+') entrou na sala');

exit;

end;

//////////////////////////////////////////////////////////////////////////////////////


//mensagem para todos////////////////////////////////////////////////////////////////

if pos('##MSG##',textorecebido)<>0 then

begin

textorecebido:=copy(textorecebido, pos('##MSG##',textorecebido)+length('##MSG##'), length(textorecebido));


for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.socket.Connections[i].SendText(textorecebido);


memoMsgs.Lines.Add(textorecebido);

exit;

end;

/////////////////////////////////////////////////////////////////////////////////////


//mensagem privada///////////////////////////////////////////////////////////////////

if pos('##MSGPVT##',textorecebido)<>0 then

begin

usuario_pvt:=StrToInt( copy( textorecebido, pos('#*',textorecebido)+length('#*'), pos('*#',textorecebido) - (pos('#*',textorecebido)+length('#*')) ));

delete(textorecebido, pos('::nick2::',textorecebido),length('::nick2::') );

delete(textorecebido, pos('::/nick2::',textorecebido),length('::/nick2::') );

textorecebido:=copy( textorecebido, pos('*#',textorecebido)+length('*#'), length(textorecebido) );

servidor.Socket.Connections[usuario_pvt].SendText(textorecebido);

memoMsgs.Lines.Add(textorecebido);

exit;

end;

/////////////////////////////////////////////////////////////////////////////////////

end;




procedure TfrmServidor.btnLimparMsgsClick(Sender: TObject);

begin

memoMsgs.Clear;

end;


procedure TfrmServidor.btnLimparStatusClick(Sender: TObject);

begin

memoStatus.Clear;

end;


procedure TfrmServidor.FormShow(Sender: TObject);

begin

frmServidor.Caption:='Chat ::ProgMaster:: (Servidor) - Status do servidor: INATIVO - por Marcísio Souza';


id_conexao_usuario:=-1;

cboxPVT.enabled:=false;

cboxPVT.checked:=false;

edtPorta.ReadOnly:=false;

pnlAtual.Caption:='Todos';

end;


procedure TfrmServidor.FormClose(Sender: TObject;

var Action: TCloseAction);

var

i : integer;

begin


if servidor.Active=true then

for i:=0 to servidor.socket.activeconnections-1 do

servidor.Socket.connections[i].SendText('##SERVIDOR_DESLIGADO##AVISO: O servidor foi fechado.');


Servidor.Active:=false;

application.Terminate;

end;


procedure TfrmServidor.LVCustomDrawItem(Sender: TCustomListView;

Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);

begin

with LV.Canvas.Brush do

begin

if (Item.Index mod 2) = 0 then

Color := clGradientInactiveCaption

else

Color := clWhite;

end;

end;


procedure TfrmServidor.cboxPVTClick(Sender: TObject);

begin

cboxPVT.enabled:=false;

pnlAtual.Caption:='Todos';

id_conexao_usuario:=-1;

memoMsg.SetFocus;

end;


procedure TfrmServidor.ClienteConnect(Sender: TObject;

Socket: TCustomWinSocket);

var

ip_internet : string;

begin

if retorna_ip_internet<>'' then

ip_internet:=retorna_ip_internet

else

ip_internet:='Sem Conexão';


socket.SendText('##NICK##'+pnlNick.Caption+'//'+ip_internet+'##QUERO_LISTA##');

end;


procedure TfrmServidor.ServidorClientDisconnect(Sender: TObject;

Socket: TCustomWinSocket);

var

L : TListItem;

i : integer;

begin

L:=lv.FindCaption(0,inttostr(socket.Handle),false,true,false);

if L<>nil then

L.Delete;


for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.Socket.Connections[i].SendText('##DESCONECTOU##'+inttostr(socket.Handle));


memoStatus.Lines.Add('Usuário desconectado: '+ Socket.RemoteAddress);

end;




procedure TfrmServidor.ServidorClientError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

var

L : TListItem;

i : integer;

begin

errorcode:=0;

L:=lv.FindCaption(0,inttostr(socket.Handle),false,true,false);

if L<>nil then

L.Delete;

for i:=0 to servidor.Socket.ActiveConnections-1 do

servidor.Socket.Connections[i].SendText('##ERRO##'+inttostr(socket.Handle)+'//'+pnlNick.Caption);


memoStatus.Lines.Add('Usuário desconectado por erro: '+ Socket.RemoteAddress);

end;



procedure TfrmServidor.ClienteRead(Sender: TObject;

Socket: TCustomWinSocket);

var

textorecebido: string;

begin

textorecebido:=socket.ReceiveText;


if ( (pos('##LISTA_USUARIOS##',textorecebido)<>0) and (pos('$:$:',textorecebido)<>0) ) then

begin

textorecebido:=copy(textorecebido , pos('$:$:',textorecebido)+length('$:$:'),length(textorecebido));

memoStatus.Lines.Add(textorecebido);

FlashWindow(Application.Handle, True);//faz a janela na barra de tarefas piscar

exit;

end;


end;



procedure TfrmServidor.ClienteError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

begin

errorcode:=0;

end;


procedure TfrmServidor.memoMsgKeyPress(Sender: TObject; var Key: Char);

begin


if ( (key=#13) and (trim(memoMsg.Text)='') or (cliente.Active=false) ) then

key:=#0;


if ( (key=#13) and (key=#17) ) then

memoMsg.Lines.Add(#13);


if ( (key=#13) and (trim(memoMsg.Text)<>'') and (cliente.Active=true) ) then

begin

if ( (cboxPVT.Checked=false) and (id_conexao_usuario=-1) ) then

begin

cliente.Socket.SendText('##MSG##'+pnlNICK.caption+' fala para TODOS: '+memoMSG.Text);

memoMsg.Clear;

end;


if ( (cboxPVT.Checked=true) and (id_conexao_usuario<>-1) ) then//msg particular (pvt)

begin

cliente.Socket.SendText('##MSGPVT##'+'#*'+inttostr(id_conexao_usuario)+'*#'+ pnlNICK.caption+' fala (em PVT) para ::nick2::'+pnlAtual.Caption+'::/nick2::: '+memoMSG.Text);

memoMsg.Clear;

end;

key:=#0;

end

else

exit;

end;


end.


O source do Servidor está aqui: http://rapidshare.com/files/455010384/Servidor.rar

com isso finalizamos a parte do Servidor do nosso chat...depois vem a parte do Cliente.

Voce pode testar usando o Telnet para enviar msgs para o servidor do chat.

OBS : Se voce utiliza roteador, é necessaria abrir a porta que utilizara no chat em seu roteador, geralmente esta em PORT FORWARD ou encaminhamento de portas... se nao fizer isso NÃO funcionará.Já se for conexao em bridge, nao há problema algum.

Agora vamos para o Cliente do chat:

Os mesmos passos do Servidor serão adotados no Cliente do nosso chat, apenas com a modificação de algumas coisa...Agora o projeto sera criado na pasta Cliente do chat.

1 groupbox com o nome de gbUsers e caption Usuários conectados.Dentro dele ponha um listview com o nome de LV, adicione as seguintes colunas nesse LV:

ID,Nick.

Ponha dois panels, um com o nome de pnlNick e outro com o nome de pnlAtual.

1 groupbox com o nome de gbMsgs com caption Mensagens e dentro dele um memo com o nome memoMsgs e propriedade align=AlClient.

1 LabeledEdit com o nome de edtServidor e o caption de IP/Host do servidor

1 LabeledEdit com o nome de edtNick e o caption de Nick

1 groupbox com o nome de gbMsg com caption Enviar mensagem e dentro dele um memo com o nome de memoMsg e a propriedade scrollbars=ssVertical e um checkbox com o nome de cboxPVT.

1 groupbox com o nome gbCfg com caption Opções do servidor e dentro dele um LabeledEdit com o nome edtPorta e labeledcaption=Porta e também um bitbtn com o nome de btnConectar e caption=Conectar.

1 groupbox com o nome de gbStatus com caption=Status e dentro dele um memo com nome de memoStatus e a propriedade align=AlClient.

1 ClientSocket com o nome de Cliente

Seu formulário deve ficar parecido com isso aqui :

http://img339.imageshack.us/i/28254369.jpg/

Codificando...a logica é a mesma do servidor galera, como eu disse, prestando bem atençao da pra entender os protocolos que utilizei na comunicaçao.

Eis o codigo completo:

unit UnitCliente;


interface


uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, ScktComp, StdCtrls, ExtCtrls, ComCtrls, Buttons, ShellApi, Winsock;


type

TfrmCliente = class(TForm)

gbMsgs: TGroupBox;

memoMsgs: TMemo;

gbCfg: TGroupBox;

btnConectar: TBitBtn;

edtPorta: TLabeledEdit;

gbStatus: TGroupBox;

MemoStatus: TMemo;

edtServidor: TLabeledEdit;

gbUsers: TGroupBox;

LV: TListView;

pnlNick: TPanel;

pnlAtual: TPanel;

gbMsg: TGroupBox;

cboxPVT: TCheckBox;

memoMsg: TMemo;

Cliente: TClientSocket;

edtNick: TLabeledEdit;

Panel1: TPanel;

function GetIP:string;

procedure AtivarDesativarCliente;

procedure ClienteConnect(Sender: TObject; Socket: TCustomWinSocket);

procedure ClienteError(Sender: TObject; Socket: TCustomWinSocket;

ErrorEvent: TErrorEvent; var ErrorCode: Integer);

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

procedure btnConectarClick(Sender: TObject);

procedure FormShow(Sender: TObject);

procedure LVClick(Sender: TObject);

procedure cboxPVTClick(Sender: TObject);

procedure memoMsgKeyPress(Sender: TObject; var Key: Char);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure LVCustomDrawItem(Sender: TCustomListView; Item: TListItem;

State: TCustomDrawState; var DefaultDraw: Boolean);

procedure edtNickChange(Sender: TObject);

private

{ Private declarations }

public

id_conexao_usuario : integer;

usuario : string;

temp,temp2, textorecebido : string;

{ Public declarations }

end;


var

frmCliente: TfrmCliente;


implementation


{$R *.dfm}


procedure ReiniciarAplicacao;

var AppName : PChar;

begin

AppName := PChar(Application.ExeName) ;

ShellExecute(0,'open', AppName, nil, nil, SW_SHOWNORMAL) ;

Application.Terminate;

end;


function TfrmCliente.GetIP:string;

//--> Declare a Winsock na clausula uses da unit

var

WSAData: TWSAData;

HostEnt: PHostEnt;

Name:string;

begin

WSAStartup(2, WSAData);

SetLength(Name, 255);

Gethostname(PChar(Name), 255);

SetLength(Name, StrLen(PChar(Name)));

HostEnt := gethostbyname(PChar(Name));

with HostEnt^ do

begin

Result := Format('%d.%d.%d.%d',

[Byte(h_addr^[0]),Byte(h_addr^[1]),

Byte(h_addr^[2]),Byte(h_addr^[3])]);

end;

WSACleanup;

end;


procedure TfrmCliente.AtivarDesativarCliente;

begin

if cliente.Active=true then

begin

lv.Clear;

cliente.Active:=false;

btnConectar.Caption:='Conectar';

frmCliente.Caption:='Chat ::ProgMaster:: (Cliente) - Status do cliente: DESCONECTADO - por Marcísio Souza';

edtPorta.ReadOnly:=false;

edtServidor.ReadOnly:=false;

edtNick.ReadOnly:=false;

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

memoMsgs.Clear;

memoStatus.Clear;

memoMsgs.Lines.Add('Conexão terminada em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.Lines.Add('Volte sempre '+pnlNick.Caption);

memoStatus.Lines.Add('Desconectado.');

end

else

begin

lv.Clear;

cliente.Host:=edtServidor.Text;

cliente.Port:=strtoint(edtPorta.text);

cliente.Active:=true;

edtPorta.ReadOnly:=true;

edtServidor.ReadOnly:=true;

edtNick.ReadOnly:=true;

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

btnConectar.Caption:='Desconectar';

frmCliente.Caption:='Chat ::ProgMaster:: (Cliente) - Status do cliente: cliente CONECTADO na porta '+edtPorta.Text+' em ('+edtServidor.Text+') - por Marcísio Souza';

memoMsgs.Clear;

memoStatus.Clear;

memoMsgs.Lines.Add('Conexão iniciada em '+datetostr(date)+' às '+timetostr(time)+'h');

memoMsgs.Lines.Add('Bem-vindo '+pnlNick.Caption);

end;

end;




procedure TfrmCliente.ClienteConnect(Sender: TObject;

Socket: TCustomWinSocket);

begin

memoStatus.Lines.Add('Conectado.');

cliente.Socket.SendText('##NICK##'+pnlNICK.Caption+'//'+socket.RemoteAddress+'##QUERO_LISTA##');

end;


procedure TfrmCliente.ClienteError(Sender: TObject;

Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;

var ErrorCode: Integer);

begin

errorcode:=0;

memoStatus.Lines.Add('ERRO ao conectar-se a: '+cliente.Host);

memoMsgs.Clear;

memoMsgs.Clear;

Cliente.Active:=false;

edtPorta.ReadOnly:=false;

edtServidor.ReadOnly:=false;

edtNick.ReadOnly:=false;

btnConectar.Caption:='Conectar';

cboxPVT.Checked:=false;

cboxPVT.Enabled:=false;

id_conexao_usuario:=-1;

pnlAtual.Caption:='Todos';

end;


procedure TfrmCliente.ClienteRead(Sender: TObject;

Socket: TCustomWinSocket);

var

i,cont : integer;

idsocket, nick : string;

l : TListItem;

begin

cont:=0;

textorecebido:=socket.ReceiveText;

temp:=textorecebido;

temp2:=textorecebido;



if pos('##LISTA_USUARIOS##',textorecebido)<>0 then

try

lv.Items.Clear;

delete(temp,1,18);

delete(temp, pos('$:$:',temp), length(temp));

/////contagem de nicks

while (pos('-_-_-',temp)<>0) do

begin

cont:=cont+1;

delete(temp,pos('-_-_-',temp),length('-_-_-'));

if (pos('-_-_-',temp)=0) then

break;

end;

/////////////////////

delete(textorecebido, pos('$:$:',textorecebido), length(textorecebido));

for i:=0 to cont-1 do

begin

idsocket:=copy(textorecebido, (pos('-_-_-',textorecebido)+length('-_-_-')),(pos('//\\',textorecebido)-(pos('-_-_-',textorecebido)+length('-_-_-'))));

delete(textorecebido,1, (pos('//\\',textorecebido)-1));

if i<>cont-1 then

begin

nick:=copy( textorecebido, pos('//\\',textorecebido) + length('//\\') , pos('-_-_-',textorecebido) - ( pos('//\\',textorecebido) + length('//\\') ));

delete(textorecebido,1,(pos('-_-_-',textorecebido)-1));

end

else

begin

nick:=copy( textorecebido, pos('//\\',textorecebido) + length('//\\') , length(textorecebido) );

delete(textorecebido,1,length(textorecebido));

end;

l:=lv.Items.Add;

l.Caption:=idsocket;

l.SubItems.Add(nick);

end;

memoStatus.Lines.Add( copy(temp2, pos('$:$:',temp2)+length('$:$:'), length(temp2)) );

exit;

except

end;


if pos('##DESCONECTOU##',textorecebido)<>0 then

begin

idsocket:=copy(temp, pos('##DESCONECTOU##',textorecebido) + length('##DESCONECTOU##'), length(temp));

L:=lv.FindCaption(0,idsocket,false,true,false);

if L<>nil then

L.Delete;

memoStatus.Lines.Add('Usuário desconectado: '+idsocket);

exit;

end;


if pos('##ERRO##',textorecebido)<>0 then

begin

idsocket:=copy(temp, pos('##ERRO##',textorecebido) + length('##ERRO##'), length(temp));

L:=lv.FindCaption(0,idsocket,false,true,false);

if L<>nil then

L.Delete;

memoStatus.Lines.Add('Usuário desconectado por erro: '+idsocket);

exit;

end;


if pos('##KICK##',textorecebido)<>0 then

begin

AtivarDesativarCliente;

application.MessageBox(PCHAR('Motivo: '+copy( textorecebido, pos('##KICK##',textorecebido)+length('##KICK##'), length(textorecebido) )), 'Você foi kickado por AdminSERVER', mb_iconwarning);

exit;

end;


if pos('##BAN##',textorecebido)<>0 then

begin

cliente.Active:=false;

application.MessageBox(PCHAR('Motivo: '+copy( textorecebido, pos('##BAN##',textorecebido)+length('##BAN##'), length(textorecebido) )), 'Você foi banido por AdminSERVER', mb_iconwarning);


ReiniciarAplicacao;

exit;

end;


if pos('##SERVIDOR_DESLIGADO##',textorecebido)<>0 then

begin

AtivarDesativarCliente;

textorecebido:=copy(textorecebido, pos('##SERVIDOR_DESLIGADO##',textorecebido)+length('##SERVIDOR_DESLIGADO##'), length(textorecebido));

memoMsgs.Lines.Add(textorecebido);

exit;

end;


memoMsgs.Lines.Add(textorecebido);

FlashWindow(Application.Handle, True);//faz a janela na barra de tarefas piscar

end;




procedure TfrmCliente.btnConectarClick(Sender: TObject);

begin

if ((edtPorta.Text<>'') and (edtServidor.Text<>'') and (edtNick.Text<>'') ) then

AtivarDesativarCliente

else

begin

application.MessageBox('O servidor e/ou nickname e/ou porta está em branco','Não permitido',mb_iconwarning);

edtServidor.SetFocus;

exit;

end;

end;


procedure TfrmCliente.FormShow(Sender: TObject);

begin

frmCliente.Caption:='Chat ::ProgMaster:: (Cliente) - Status do cliente: DESCONECTADO - por Marcísio Souza';

edtServidor.SetFocus;

edtNick.Clear;

pnlNick.Caption:='';

cboxPVT.enabled:=false;

cboxPVT.checked:=false;

edtPorta.ReadOnly:=false;

pnlAtual.Caption:='Todos';

id_conexao_usuario:=-1;

end;


procedure TfrmCliente.LVClick(Sender: TObject);

begin


if lv.ItemIndex=-1 then

exit;


cboxPVT.Checked:=true;

cboxPVT.enabled:=true;

pnlAtual.Caption:=lv.Selected.SubItems.Strings[0];

id_conexao_usuario:=lv.ItemIndex;

memoMsg.SetFocus;

exit;

end;


procedure TfrmCliente.cboxPVTClick(Sender: TObject);

begin

cboxPVT.enabled:=false;

pnlAtual.Caption:='Todos';

id_conexao_usuario:=-1;

memoMsg.SetFocus;

end;


procedure TfrmCliente.memoMsgKeyPress(Sender: TObject; var Key: Char);

begin


if ( (key=#13) and (trim(memoMsg.Text)='') or (cliente.Active=false) ) then

key:=#0;


if ( (key=#13) and (key=#17) ) then

memoMsg.Lines.Add(#13);


if ( (key=#13) and (trim(memoMsg.Text)<>'') and (cliente.Active=true) ) then

begin

if ( (cboxPVT.Checked=false) and (id_conexao_usuario=-1) ) then

begin

cliente.Socket.SendText('##MSG##'+pnlNICK.caption+' fala para TODOS: '+memoMSG.Text);

memoMsg.Clear;

end;


if ( (cboxPVT.Checked=true) and (id_conexao_usuario<>-1) ) then//msg particular (pvt)

begin

cliente.Socket.SendText('##MSGPVT##'+'#*'+inttostr(id_conexao_usuario)+'*#'+ pnlNICK.caption+' fala (em PVT) para ::nick2::'+pnlAtual.Caption+'::/nick2::: '+memoMSG.Text);

memoMsgs.Lines.Add(pnlNICK.caption+' fala (em PVT) para '+pnlAtual.Caption+': '+memoMSG.Text);

memoMsg.Clear;

end;

key:=#0;

end

else

exit;

end;


procedure TfrmCliente.FormClose(Sender: TObject; var Action: TCloseAction);

begin

cliente.Active:=false;

application.Terminate;

end;


procedure TfrmCliente.LVCustomDrawItem(Sender: TCustomListView;

Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);

begin

with LV.Canvas.Brush do

begin

if (Item.Index mod 2) = 0 then

Color := clMoneyGreen

else

Color := clWhite;

end;

end;


procedure TfrmCliente.edtNickChange(Sender: TObject);

begin

pnlNick.Caption:=edtNick.Text;

end;

end.


Source do cliente : http://rapidshare.com/files/455260888/Cliente.rar

Source completo : http://rapidshare.com/files/455261010/Chat_Intranet_sem_banco_de_dados.rar


É galera com isso finalizo a postagem..espero q gostem e que entendam como funciona, só nao vale baixar o source completo e compilar sem entender nada!!

usem a vontade mas se forem postar em algum outro canto ou forem fazer melhorias nao eskeçam dos meus creditos heheheheheeheh

Até a proxima!

7 comentários:

  1. finalmente encontrei o que eu queria!!!!!!!!!!!
    nunk ngm tinha posto um exemplo de chat realmente decente como esse ai, que faz o que promete no enunciado.
    valeu progmaster.

    ResponderExcluir
  2. Estou vendo esse post em 2013 e gostaria de saber como utilizar o sistema numa rede com proxy. Pois aqui na minha rede a conexão com a internet se dá através de um squid proxy e quando eu rodo o server(clico no botão iniciar servidor) da erro: Projetc Project1.exe raised exception class EidSochetError with message 'Socket Error #10060 Connection timed out.'. Process stopped. Use Step or Run to continue.

    Desde já grato!

    ResponderExcluir
  3. mano poste o cliente pf

    ResponderExcluir
  4. Poderia posta o chat completo feito? pois tentei fazer e nao funciona fica dando erro

    ResponderExcluir
  5. Tutorial perfeito. Bem apresentado. Sem erros. E muito objetivo. Parabéns!!!

    ResponderExcluir

Popular Posts

 

Seguidores

Hora exata:

Total de visualizações de página