Implementando um chat via servlets  XML
Índice dos Fóruns » Java Avançado
Autor Mensagem
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

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

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
Paulo Silveira
Administrador
[Avatar]

Membro desde: 07/08/2002 18:38:50
Mensagens: 4204
Localização: São Paulo
Offline

Tenho uma solucao mais legal ainda!

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




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:



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:



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

legal neh?

http://blog.caelum.com.br twitter: @paulo_caelum


[Email] [WWW]
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

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

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
Paulo Silveira
Administrador
[Avatar]

Membro desde: 07/08/2002 18:38:50
Mensagens: 4204
Localização: São Paulo
Offline

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

http://blog.caelum.com.br twitter: @paulo_caelum


[Email] [WWW]
Paulo Silveira
Administrador
[Avatar]

Membro desde: 07/08/2002 18:38:50
Mensagens: 4204
Localização: São Paulo
Offline

Digo isto porque voce deu duas solucoes:

Guilherme Silveira wrote:
- para cada novo formulario, processar umvetor com uma lista de usuarios conectados e enviar a mensagem para cada Stream deles

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)?

Guilherme Silveira wrote:
- durante o sleep da servlet de TEXTO, checar se existe algo novo e jogar este novo no stream do usuario.

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!

http://blog.caelum.com.br twitter: @paulo_caelum


[Email] [WWW]
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

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:

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.


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

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
Paulo Silveira
Administrador
[Avatar]

Membro desde: 07/08/2002 18:38:50
Mensagens: 4204
Localização: São Paulo
Offline

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

Voce pode fazer um singleton, se qusier disfarcar.

http://blog.caelum.com.br twitter: @paulo_caelum


[Email] [WWW]
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

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

Gui

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
Rafael Steil
Administrador
[Avatar]

Membro desde: 31/08/2002 02:35:53
Mensagens: 5984
Localização: São Paulo
Offline

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

"working code attracts people who want to code. Design documents attract people who want to talk about coding - Charles Miller"

http://rafaelsteil.com
http://twitter.com/rafaelsteil
http://www.jforum.net
http://www.flickr.com/photos/rafaelsteil
[Email] [WWW]
urubatan
Moderador
[Avatar]

Membro desde: 21/09/2002 10:31:26
Mensagens: 2481
Localização: Porto Alegre/RS
Offline

da pra fazer isto aqui mesmo com a galera

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

[]'s
Rodrigo Urubatan
http://www.urubatan.com.br
Melhor livro de RoR do brasil: http://livro.urubatan.com.br
[WWW]
aconstantino
Virtual Machine Man
[Avatar]

Membro desde: 14/09/2002 16:37:24
Mensagens: 698
Offline

Sabendo que deve ser o protocolo HTTP mas ja palpitando... :)

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...
[Email] [WWW] [MSN]
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

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

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

nossa
o baguio loto de gente
e ta rapidissimo

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
jmprado
Entusiasta Java
[Avatar]

Membro desde: 18/09/2002 17:29:22
Mensagens: 16
Localização: Belo Horizonte - MG
Offline

java.lang.NullPointerException

quando enviei um texto para "todos" no chat

______________
< Java não é uma linguagem. É um paradigma. />
Paulo Silveira
Administrador
[Avatar]

Membro desde: 07/08/2002 18:38:50
Mensagens: 4204
Localização: São Paulo
Offline

hehehe
ta dando NullPointer agora mesmo!

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

http://blog.caelum.com.br twitter: @paulo_caelum


[Email] [WWW]
 
Índice dos Fóruns » Java Avançado
Ir para:   
Powered by JForum 2.1.8 © JForum Team