Situação: há um server, que controla todas as conexões dos clients, cada client reside em um thread do server.
Até aqui ótimo.
Mas a dúvida é: Ao receber uma mensagem de um client (que reside num thread) como fazer para o server enviar esta mensagem para os outros client (que estão em outro threads)?
Situação: há um server, que controla todas as conexões dos clients, cada client reside em um thread do server.
Até aqui ótimo.
Mas a dúvida é: Ao receber uma mensagem de um client (que reside num thread) como fazer para o server enviar esta mensagem para os outros client (que estão em outro threads)?
Uma ideia:
Quando o cara se conectar voce joga a thread dele e um identificador (pode ser o IP p.ex.) numa colecao. Em cada mensagem voce envia o identificador do destinatario. Quando o servidor receber uma mensagem voce pega o identificador, resgata a thread do destinatario e dispara a mensagem para ele.
Estou imaginando que essa “thread” que voce mencionou seja um objeto com o qual voce consiga se comunicar com o cliente, certo?
Depois diz pra gente se esse barato funcionou… Voce ta fazendo um chat? Tenho interesse nesse assunto.
Marcio Kuchma
_fs
Então cara, o problema é anterior a esse que você já ajudou a solucionar hehe ainda não preciso selecionar qual client receber qual mensagem. Apenas mandar a mensagem para todo mundo hehe
Aqui está o código do server:
packagechat;importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;importjava.io.*;importjava.net.*;importjava.awt.*;importjava.awt.event.*;importjavax.swing.*;publicclassServerextendsJFrame{protectedJTextAreadisplay;privateintConns=50;privateVipvip[];privateServerSocketserver;protectedBufferedReaderinput;protectedPrintWriteroutput;intinumClient;publicServer(){super("Server");vip=newVip[Conns];try{server=newServerSocket(60000,Conns);}catch(IOExceptione){e.printStackTrace();System.exit(1);}Containerc=getContentPane();display=newJTextArea();c.add(newJScrollPane(display),BorderLayout.CENTER);setSize(300,150);show();}protectedvoidfinalize(){// Objects created in run method are finalized when // program terminates and thread exitstry{server.close();}catch(IOExceptione){System.out.println("Could not close socket");System.exit(-1);}}publicvoidexecute(){for(inti=0;i<=Conns;i++){try{vip[i]=newVip(server.accept(),this);vip[i].start();System.out.println(i);inumClient++;}catch(IOExceptione){e.printStackTrace();System.exit(1);}}}publicstaticvoidmain(Stringargs[])throwsIOException{Serverchat=newServer();chat.addWindowListener(newWindowAdapter(){publicvoidwindowClosing(WindowEvente){System.exit(0);}});chat.execute();}}classVipextendsThread{privateSocketskt;protectedBufferedReaderinput;protectedPrintWriteroutput;privateServers;publicVip(Socketsock,Serverserv){skt=sock;s=serv;}publicvoidrun(){Stringmessage="";try{skt.setTcpNoDelay(true);// http://jguru.com/faq/view.jsp?EID=42242s.display.append("Esperando uma conexão");output=newPrintWriter(skt.getOutputStream());input=newBufferedReader(newInputStreamReader(skt.getInputStream()));s.display.append("Got I/O streams");s.display.append("Conexão bem sucedida. De client nº "+s.inumClient+"");while(!message.equals("a")){message=(String)input.readLine();if(!message.equals("")){s.display.append(""+message);s.display.setCaretPosition(s.display.getText().length());}output.println("SERVER:: "+message);output.flush();}skt.close();input.close();output.close();}catch(IOExceptione){e.printStackTrace();}s.display.append("O cliente terminou a conexão.");}}
Entendeu o que quis dizer com Thread? Então, cada client que se conecta, o server cria um thread para lidar com cada um deles.
Isso faz com que a comunicação client x server seja perfeita, mas a comunicação server x clientS (plural) não existe.
A minha dúvida é como fazer o server mandar um broadcast para todos os clients.
kuchma
“LIPE”:
Isso faz com que a comunicação client x server seja perfeita, mas a comunicação server x clientS (plural) não existe.
A minha dúvida é como fazer o server mandar um broadcast para todos os clients.
Hmmm, saquei o problema.
Bom, vou ser sincero - (ainda) nao li teu codigo inteiro.
Mas pela tua duvida (melhor coisa que tem eh quando a gente consegue definir nossa duvida em poucas e claras palavras :)) eu posso sugerir duas coisas:
Veja como funciona a classe DatagramSocket e como acopla-la num endereco de multicast (um endereco de multicast eh igual um endereco comum, mas ele fica numa faixa especial - de 244.0.0.0 ate 239.255.255.255 acho). Dessa maneira voce conseguiria disparar mensagens para um endereco de multicast e todos que estivessem “ouvindo” neste endereco receberiam as mensagens. Mas nao sei como isso se encaixa no seu projeto atual - sockets de datagramas sao diferentes de stream sockets.
Outra maneira mais “tosca” seria voce percorrer sua colecao que armazenam os sockets dos clientes e enviar a mensagem para cada um individualmente. Ta, eu sei que isso nao eh broadcast, mas pode ser uma opcao.
Estou trabalhando num projeto semelhante ao teu… comente teus progressos em fazer o broadcast.
Marcio Kuchma
louds
Crie 1 fila de mensagens por cliente conectado e coloque cada thread consumindo da sua fila e produzindo para as demais.
Esse cara pega e distribui 1 objeto vindo 1 uma fila para todas as demais.
E como voce usa isso? No loop das tuas thread que ficam lendo a entrada faça assim:
kuchma - valeu mesmo, e pelo que andei pesquisando datagramSocket é realmente mais utilizado para este tipo de coisa, mas trabalhar com UDP me dá nos nervos hehe
Pode deixar que meu progresso deixará uma trilha de posts aqui
Louds - muitissimo obrigado por responder, vou estudar melhor o código que você postou, pois admito ainda não conhecer alguns conceitos que você usou. Mas o jeito que você fez realmente me parece oferecer mais controle sobre as mensagens. Valeu!
_fs
Louds … não sei como te dizer isso mas … não rolou hehe mas vou continuar nesse caminho.
ps.: sim, eu arrumei os errinhos de digitação.
louds
cara, eu não testei esse código e te digo que ele tem grande problema.
Sockets no java são blocantes, ou seja, eles ficam parados enquanto não aparecer dados para serem lidos.
E isso vai fazer meu exemplo não funcionar, já que as mensagens da fila serão somente transmitidas para o cliente quando ele mandar algo pro servidor.
Exsitem algumas formas de resolver isso:
-Use o método available() antes de read() para verificar se existem dados disponiveis para leitura no socket.
-Usar read() com timeout pequeno.
-Usar sockets não-blocantes e read() pooling
-Usar sockets não-blocantes e io multiplexing (via select)
Minha sugestão é você tentar com os 2 primeiros que são beem mais simples
_fs
Não expliquei direito quando disse que não rolou. O server manda a mensagem para o cliente, mas para 1 cliente apenas (aquele que mandou a mensagem).
Pelo fato do método dequeue ser synchonized, ele não garantiria que a ação seria realizada por todos os threads?
E, pelo que entendi, a mágica toda de mandar a mensagem para todos os clients acontece aqui, não é?
bom krinha
se vc ainda tiver duvida em relacao a isso
eu achei um negocio que pdoe te esclarecer
importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Enumeration;importjava.util.Vector;publicclassServidorDeEcoextendsThread{publicstaticvoidmain(Stringarg[]){clientes=newVector();try{//criando socket para escutar porta 40000ServerSockets=newServerSocket(40000);while(true){//aguarda alguem se conectar. A execucao do servidorSocketconexao=s.accept();//obtendo os objetos de controle de fluxo de comunicacaoThreadt=newServidorDeEco(conexao);t.start();}}catch(IOExceptione){System.out.println("IOException: "+e);}}privatestaticVectorclientes;privateSocketconexao;privateStringmeunome;publicServidorDeEco(Sockets){conexao=s;}publicvoidrun(){try{BufferedReaderentrada=newBufferedReader(newInputStreamReader(conexao.getInputStream()));PrintStreamsaida=newPrintStream(conexao.getOutputStream());meunome=entrada.readLine();if(meunome==null){return;}clientes.add(saida);Stringlinha=entrada.readLine();while(linha!=null&&!(linha.trim().equals(""))){sendToAll(saida," disse: ",linha);linha=entrada.readLine();}sendToAll(saida," saiu: "," do chat! ");clientes.remove(saida);conexao.close();}catch(IOExceptione){System.out.println("IOException: "+e);}}publicvoidsendToAll(PrintStreamsaida,Stringacao,Stringlinha)throwsIOException{Enumeratione=clientes.elements();while(e.hasMoreElements()){PrintStreamchat=(PrintStream)e.nextElement();if(chat!=saida){chat.println(meunome+acao+linha);}}}}
cliente:
importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.PrintStream;importjava.net.Socket;publicclassClientedeEcoextendsThread{privatestaticbooleandone=false;publicstaticvoidmain(Stringargs[]){try{Socketconexao=newSocket("localhost",40000);PrintStreamsaida=newPrintStream(conexao.getOutputStream());BufferedReaderteclado=newBufferedReader(newInputStreamReader(System.in));System.out.println("Entre com seu nome: ");Stringmeunome=teclado.readLine();saida.println(meunome);Threadt=newClientedeEco(conexao);t.start();Stringlinha;while(true){System.out.println(" ");linha=teclado.readLine();if(done){break;}saida.println(linha);}}catch(IOExceptione){System.out.println("IOException: "+e);}}privateSocketconexao;publicClientedeEco(Sockets){conexao=s;}publicvoidrun(){try{BufferedReaderentrada=newBufferedReader(newInputStreamReader(conexao.getInputStream()));Stringlinha;while(true){linha=entrada.readLine();if(linha==null){System.out.println("Conexao Encerrada !");break;}System.out.println();System.out.println(linha);System.out.println("...> ");}}catch(IOExceptione){System.out.println("IOException: "+e);}done=true;}}