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)?
[quote=“LIPE”]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)? [/quote]
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.
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:
package chat;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Server extends JFrame
{
protected JTextArea display;
private int Conns = 50;
private Vip vip[];
private ServerSocket server;
protected BufferedReader input;
protected PrintWriter output;
int inumClient;
public Server()
{
super( "Server" );
vip = new Vip[ Conns ];
try
{
server = new ServerSocket( 60000, Conns );
}
catch( IOException e )
{
e.printStackTrace();
System.exit( 1 );
}
Container c = getContentPane();
display = new JTextArea();
c.add( new JScrollPane( display ), BorderLayout.CENTER );
setSize( 300, 150 );
show();
}
protected void finalize()
{
// Objects created in run method are finalized when
// program terminates and thread exits
try
{
server.close();
}
catch (IOException e)
{
System.out.println("Could not close socket");
System.exit(-1);
}
}
public void execute()
{
for( int i = 0; i <= Conns; i++ )
{
try
{
vip[ i ] = new Vip( server.accept(), this );
vip[ i ].start();
System.out.println( i );
inumClient++;
}
catch( IOException e )
{
e.printStackTrace();
System.exit( 1 );
}
}
}
public static void main( String args[] ) throws IOException
{
Server chat = new Server();
chat.addWindowListener(
new WindowAdapter()
{
public void windowClosing( WindowEvent e )
{
System.exit( 0 );
}
}
);
chat.execute();
}
}
class Vip extends Thread
{
private Socket skt;
protected BufferedReader input;
protected PrintWriter output;
private Server s;
public Vip( Socket sock, Server serv )
{
skt = sock;
s = serv;
}
public void run()
{
String message = "";
try
{
skt.setTcpNoDelay(true); // http://jguru.com/faq/view.jsp?EID=42242
s.display.append( "
Esperando uma conexão
");
output = new PrintWriter( skt.getOutputStream() );
input = new BufferedReader( new InputStreamReader( 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( IOException e )
{
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.
[quote=“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.[/quote]
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.
Crie 1 fila de mensagens por cliente conectado e coloque cada thread consumindo da sua fila e produzindo para as demais.
algo +/- assim:
class Queue {
LinkedList queue = new LinkedList();
public synchronized void enqueue(Object obj) {
queue.add(obj);
}
public synchronized Object dequeue() {
if(queue.isEmpty())
return null;
return queue.removeFirst();
}
}
Coisa simples ate aqui ne?
Ok, agora voce cria 1 class que faz a multiplexagem das mensagens:
class QueueMultiplexor {
Collection queues = new HashSet();
public synchronized void register(Queue q) {
queues.add(q);
}
public syhchronized void unregister(Queue q) {
queues.remove(q);
}
public syhchronized void multiplex(Object msg, Queue source) {
for(Iterator i = queues.iterator(); i.hasNext(); ) {
Queue q = (Queue)i.next();
if(i != source)
q.enqueue(msg);
}
}
}
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!
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