Implementando um chat via servlets

Depois de uma longe discussao numa lista, decidi copiar aqui tambem o que sei sobre chats, assim quem tiver duvidas do assunto vao saber onde perguntar, se nao solucionar o problema.

Um chat que se mantem no servidor implementado por servlets/jsp costuma possuir dois frames: o TEXTO (onde tem a barra de rolagem) e o FORMULARIO. O protocolo eh sempre HTTP claro.

O formulario pode usar o metodo POST/GET mas o metodo recomendado pode ser o PUT, uma vez que indica enviar algo para alterar uma pagina.

A diferenca cosmetica numa servlet sera qual metodo devera ser implementado, doGet, doPost ou doPut.

A servlet que recebe o formulario ira processar o request e devolver um novo formulario.

Pronto, a segunda parte esta pronta, falta a primeira parte/frame.

Ele eh feito atraves de uma outra/mesma servlet que NAO FECHA A CONEXAO COM O CLIENTE (exemplos: uol, terra). Algumas pessoas pensam que isso ira abusar de conexoes, porem eh a tecnica utilizada por todos os grandes chats. Fora dessa soh existe o metodo de reloads que nem irei comentar.

Desse jeito, essa servlet mantem uma lista com os streams de saida (OutputStream/Writer) e quem eh quem (esses chats sempre fazem aquele opcao de mandar mensagem privada para “Joca Maloca”).
Essa servlet ira dormir ate o usuario clicar STOP no browser (ira jogar uma excecao no codigo: stream fora fechada) ou fechar a janela (idem)… assim voce sabe que o usuario saiu da sala. Claro que voce pode criar um botao SAIR que tambem devera tirar o usuario da sala.

Por ultimo voce precisa fazer com que a cada nova mensagem na servlet que processa FORMULARIOS, essas sejam escritas nos usuarios que estao conectados na servlet de TEXTO (se nao for a mesma).
Para isso voce pode:

  • para cada novo formulario, processar umvetor com uma lista de usuarios conectados e enviar a mensagem para cada Stream deles
  • durante o sleep da servlet de TEXTO, checar se existe algo novo e jogar este novo no stream do usuario.

O primeiro metodo eh muito mais inteligente e rapido, apesar de efetuar uma conexao direta entre duas servlets (nao muito orientado a objeto), mas eh um problema que pode ser solucionado sem muita dor de cabeca.

Bom, eh isso, espero ter solucionado o problema daqueles que nao conseguem imaginar como fazer um chat sem tempos de reload…

Quaisquer duvidas, podem escrever

Guilherme Silveira

Tenho uma solucao mais legal ainda!

Cria um objeto estatico que vai ser usado como mutex na servlet

public static Object chat = new Object();

Ai, voce usa o esquema do Guilherme, imprime tudo o que voce ja tem num buffer (static StringBuffer como variavel de classe de servlet, por exemplo), e poe diretao:

while (true) {

  synchronized(chat) {
    chat.wait();
  }

  descarregaRestoDoBuffer();

}

Assim a servlet vai ficar esperando, e várias outras vao ficar esperando. Quando alguem manda uma mensagem, atraves de outra servlet, voce sincroniza atraves dessa variavel CHAT, e da um notifyAll:

ServletDeChat.bufferEstatico.append(mensagem);
synchronized(chat) {
  chat.notifyAll();
}

Todo mundo vai sair do Wait! Ai la voce le o que o cara colocou no buffer, e volta pro wait!

legal neh?

essa eh a complicacao q eu falei q nao seria o problema de uma grande dor de cabeca…

mas com certeza ainda acho melhor criar um objeto chamado Cliente ou Usuario com um metodo addMessage() e passa um objeto Message() para ele.
Esse metodo deve entao simplesmente processar essa mensagem.
Eh mais orientado a objeto do que a tua solucioneba meia boca (to brincando)

Gui

Mas entao no seu caso, as servlets ficam o tempo TODO verificando se tem mensagem nova? Isso eh loucura total! PRECISA de sincronização.

Digo isto porque voce deu duas solucoes:

Ok, voce envia a mansagem pro stream do cliente. Mas como a thread q ta servindo esse cliente vai descobrir que o stream tem coisa nova? Voce fica dentro de um while(true)?

Esta aqui é muito ruim! De quanto tempo eh o sleep? Se for pouco, vai sobrecarregar o servidor. Se for muito, vai ter lag na conversa!

esse segundo q vc falou era o meu primeiro q eu descartei la no texto
o primeiro q vc falou eh o meu segundo no texto q eu adicionei:

que eh exatamente o q vc fez, efetuou a conexao direta enter as duas servlets atraves de um objeto/metodo estatico das duas.
o melhor ainda seria que esse fizesse esse metodo/objeto estatico um pouco mais orientado a objeto e nao soh um simples mutex inutilex

gui

Mas o seu vetor de OutputStreams (buffers) dos clientes eh estatico.
Nao tem como fugir.

Voce pode fazer um singleton, se qusier disfarcar.

o vetor eh estatico mas nao visivel atraves de um getVector()
e sim teria um estatico sendMessageToUser(User,Message);

Gui

Eu tambem quero ter um irmao programador pra mim poder ficar discutindo metodologias de desenvolvimento com ele e outras noias do genero… :mrgreen:

da pra fazer isto aqui mesmo com a galera :slight_smile:

perdi o inicio da conversa, mas eu utilizaria a opção mais orientada a objeto mencionada,
com um unico metodo estatico, para adicionar o texto das novas mensagens nos buffers de cada cliente.

ai sincronizaria apenas por este metodo :slight_smile:

Sabendo que deve ser o protocolo HTTP mas ja palpitando… :slight_smile:

No meu ponto de vista a melhor forma é criar um protocolo próprio para o chat (já que o chat em discussão é um chat de grande porte) com encriptação e um servidor distribuindo para os clientes a grande idéia do servidor também é só receber conexões de uma rede local.

Ai então criando o socket poderiamos iniciar o servelet.Uma thread enviando e recebendo dados (isto configurado o timeout do socket ) caso dê timout o usuário é automaticamente desconectado da rede.

Isto por ser bom também para evitar os espertinhos que adoram fazer softwares para conexão em chats do UOL etc…

Olha gente, ja terminei o chat que vou usar de exemplo no tutorial, ele nao tem suporte pra salas mas pode ser facilmente adaptado.
Estarei escrevendo agora o tutorial e creio que na sexta terei ele pronto.

Para acessar o chat de exemplo basta incluir teu login no lugar do “SEULOGINAQUI”!

http://www.guj.com.br/servlet/br.guj.chat.ChatServlet?login=SEULOGINAQUI

Abraco

Guilherme

nossa
o baguio loto de gente
e ta rapidissimo

java.lang.NullPointerException

quando enviei um texto para “todos” no chat

hehehe
ta dando NullPointer agora mesmo!

Gui, pode apostar que eh cosia do GarbageCollector, ou coisa dos OutputStreams que fecham depois de um tempo!

O Chat nao funciona no meu browser. To usando o galeon 1.2.5 ( q usa como base o mozilla 1.0 ), e ao inves de aparecer os frames, aparece na tela os codigos html … deu pau la no trampo e aki em casa.

Rafael

ele nao deve ter setado o content type, ou nao ta de acordo com o w3c

esses browsers, tipo lynx e w3m, sao mto chatos

Galera, este chat fará parte do GUJ ?? É uma ótima ideia !

Das veiz (sotaque mineiro) acontece de esquecer di inicializar alguma coisa e da esse pau, quem sabe num eh coisa simplis…

oi gente
entao, eu mudei um baguio e mandei la e esqueci de testa, meio cabecao neh…
de qq jeito, ta la uma versao q deve rodar
com certeza eu nao setei o content type e nem to muito afim de incluir a linha hoje la nao aehuaeuhaeuhhae… preguica mata
talvez amanha…

gui