aplicação cliente/servidor

36 respostas
E

Bom dia

Não tenho muita experiencia em programação
Estou desenvolvendo uma aplicação cliente servidor com socket e gostaria de saber como posso verificar os usuarios que estão conectados para escolher para quem devo mandar as mensagens , já está funcionando como se fosse um chat.

Obrigada

Aguardo

Qualquer coisa posto o codigo para facilitar

36 Respostas

D

Desenvolvi uma aplicação semelhante a pouco tempo.
Havia um método através do qual o cliente efetuava login. Neste momento, o servidor adicionava este cliente a uma lista de clientes ativos. Caso o cliente permanecesse mais do que alguns segundos sem atividade alguma, ele era considerado inativo e retirado desta lista.
Havia também um método através do qual o cliente obtinha uma lista com os usuários ativos.

E

Assim mesmo que preciso

Teria como você me ajudar fazer isso?

D

Posso tentar de ajudar.
Qual sua dúvida?
Você já iniciou o projeto?

F

É isso ai, dê mais detalhes…quem sabe eu também não dou uns “toques”.

flws

E

então gente

Já consegui fazer o cliente / servidor se comunicarem, mas ele manda mensgem para todos que estão conectados

quer q poste o codigos do cliente e do servidor?

F

Se vc puder fazer esta gentileza, seria ótimo.

flws

E

Os codigos são : mas ainda terá algumas modificações, pois peguei como base um q faz por console e coloquei interface grafica

Servidor

package Client;

import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;

public class chatserver extends Thread
{
  int DEFAULT_PORT=4321;
  protected int port;
  protected ServerSocket server_port;
  protected ThreadGroup CurrentConnections;
  protected Vector connections;
  protected ServerWriter writer;
  private Calendar datatual;

  //Criar um ServerSocket
  public chatserver()
  {
    super("Server");
    this.port=DEFAULT_PORT;
    try
    {
      server_port=new ServerSocket(port);
    }
    catch (IOException e)
    {
      System.err.println(e+"Exception");
    }
    //Cria um threadgroup para as conexoes
    CurrentConnections=new ThreadGroup("Server Connections");

    //Mensagem inicial na janela do servidor
    System.out.println("::.. Conexoes Realizadas ..::");

    //Um vetor para armazenar as conexoes
    connections=new Vector();
    writer=new ServerWriter(this);

    //Inicia o servidor para ouvindo as conexoes
    this.start();
  }

  public void run()
  {
    try
    {
      while(true)
      {
        datatual = Calendar.getInstance();
        Socket cliente_socket=server_port.accept();
        //Exibe na janela do servidor os clientes que conectam (mostra o host
        //do cliente, a porta e a data e hora da conexao 
        System.out.println("Host:"+cliente_socket.getInetAddress()+"³ Porta:"+
                            cliente_socket.getPort()+"³ "+datatual.getTime());
        Connection c=new Connection(cliente_socket,CurrentConnections,3,writer);
        //evita o acesso simultaneo
        synchronized(connections)
        {
          //adiciona esta nova conexao a lista
          connections.addElement(c);
        }
      }
    }
    catch(IOException e)
    {
      System.err.println(e+"Exception");
    }
  }

  //Inicia o servidor
  public static void main(String[] args)
  {
    new chatserver();
  }
}
//----------------------------------------------------------------------------
class Connection extends Thread
{
  static int numberOfConnections=0;
  protected Socket client;
  protected DataInputStream in;
  protected PrintStream out;
  protected ServerWriter writer;

  public Connection(Socket cliente_socket, ThreadGroup CurrentConnections,
                 int priority, ServerWriter writer)
  {
    super(CurrentConnections,"Connection number"+numberOfConnections++);
    //define a prioridade
    this.setPriority(priority);
    client=cliente_socket;
    this.writer=writer;
    try
    {
      //Atarraxa os streams aos streams de entrada e saida do socket do
      //cliente e adiciona este outputstream ao vetor que contem todos
      //os streams de saida, usados pelo escritor writer
      in=new DataInputStream(client.getInputStream());
      out=new PrintStream(client.getOutputStream());
      writer.OutputStreams.addElement(out);
    }
    catch(IOException e)
    {
      try
      {
        client.close();
      }
      catch (IOException e2)
      {
        System.err.println("Exception while getting socket streams:"+e);
        return;
      }
    }
    //dispara Thread
    this.start();
  }

  //O metodo run faz um laco lendo as mensagens recebidas
  public void run()
  {
    String inline;
    //Envia uma mensagem de boas vindas ao cliente
    out.println("Bem vindo ao Comunicador Instântaneo...");
    try
    {
      while(true)
      {
        //le uma linha de mensagem
        inline=in.readLine();
        //A conexao eh interrompida se null
        if (inline==null)
          break;
        //Joga a linha no escritor writer
        writer.setOutdata(inline);
        synchronized(writer)
        {
          //chama o escritor synchronized() para evitar que duas linhas
          //Connection o chamem ao mesmo tempo. Esta e uma forma de "bloqueio".
          writer.notify();
        }
      }
    }
    catch(IOException e)
    {}
    finally
    {
      try
      {
        client.close();
      }
      catch(IOException e2)
      {}
    }
  }
}
//----------------------------------------------------------------------------
class ServerWriter extends Thread
{
  protected chatserver server;
  public Vector OutputStreams;
  public String outdata;
  private String outputline;

  public ServerWriter(chatserver s)
  {
    super(s.CurrentConnections,"Server Writer");
    server=s;
    OutputStreams=new Vector();
    this.start();
  }

  public void setOutdata(String mensagem)
  {
    outdata=mensagem;
  }

  public synchronized void run()
  {
    while(true)
    {
      //A linha faz um laco para sempre, mas na vedade so e executada quando
      //a condicao wait for reinicializada por um notify. Isso num bloco
      //sincronizado para bloquear a linha e evitar o acesso multiplo.
      try
      {
        this.wait();
      }
      catch (InterruptedException e)
      {
        System.out.println("Caught an Interrupted Exception");
      }
      outputline=outdata;
      synchronized(server.connections)
      {
        for (int i=0 ; i<OutputStreams.size() ; i++)
        {
          //Eh impressa a mensagem em cada um OutputStreams.
          PrintStream out;
          out=(PrintStream)OutputStreams.elementAt(i);
          out.println(outputline);
        }
      }
    }
  }
}

Cliente

import java.awt.Button;
import java.awt.Container;
import java.awt.Event;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Label;
import java.awt.ScrollPane;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class ClienteCall extends JFrame implements ActionListener {

	public static final int DEFAULT_PORT = 4321;
	public Socket clisoc;
	private Thread reader;
	public PrintStream out;
	public String Name;

	// Criação dos objetos da tela
	private Label lb1;
	private Label lb2;
	private Button b1;
	private Button b2;
	private static TextField tf1;
	private TextField InputArea;
	private TextArea OutputArea;
	private ScrollPane sp1;

	public ClienteCall() {
		setTitle("::.. Comunicador Instântaneo ..::");
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		setExtendedState(MAXIMIZED_BOTH);
		setResizable(false);

		setLocationRelativeTo(null);
		// Cria as linhas de leitura e escrita e as inicia.

		lb1 = new Label("::.. MiniChat Conexão Socket ..::");
		lb2 = new Label("Nome do usuario");
		b1 = new Button("Limpar");
		b2 = new Button("Sair");
		OutputArea = new TextArea(10, 45);
		InputArea = new TextField(20);
		tf1 = new TextField(15);
		// sp1 = new JScrollPane(OutputArea);

		Container janela = getContentPane();
		janela.setLayout(new FlowLayout());

		// Formatando Fonte
		OutputArea.setFont(new Font("Serif", Font.ITALIC, 16));
		tf1.setFont(new Font("Serif", Font.ITALIC, 16));

		// Adicionando scrollPane - barra de rolagem automatica
		// sp1
		// .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

		// Adicionado componentes
		janela.add(lb1);
		janela.add(lb2);
		janela.add(tf1);
		janela.add(OutputArea);
		janela.add(new Label("Digite a mensagem e pressione ENTER"));
		janela.add(InputArea);
		janela.add(b1);
		janela.add(b2);

		// Dimensões Janela
		setSize(550, 350);

		// Ações Botões
		b1.addActionListener(this);
		b2.addActionListener(this);

		try {
			// Cria um socket cliente passando o endereco e a porta do servidor
			clisoc = new Socket("127.0.0.1", DEFAULT_PORT);
			reader = new Reader(this, OutputArea);
			out = new PrintStream(clisoc.getOutputStream());
			// Define prioridades desiguais para que o console seja
			// compartilhado
			// de forma efetiva.
			reader.setPriority(3);
			reader.start();
		} catch (IOException e) {
			System.err.println(e);
		}
	}


	public boolean handleEvent(Event evt) {
		if (evt.target == InputArea) {
			char c = (char) evt.key;

			if (c == '\n')
			// Vigia se o usuario pressiona a tecla ENTER.
			// Isso permite saber a mensagem esta pronta para ser enviada!
			{
				String InLine = InputArea.getText();

				Name = tf1.getText();

				out.println(Name + ":" + InLine);

				InputArea.setText("");

				// Envia a mensagem, mas adiciona o nome do usuario a ela para
				// que os
				// outros clientes saibam quem a enviou.
				return true;
			}
		}
		return false;
	}
	 

	public void actionPerformed(ActionEvent e) {

		if (e.getSource() == b1) {
			InputArea.setText("");

		}
		if (e.getSource() == b2) {
			System.exit(0);

		}
	}

	public static void main(String[] args) {
		ClienteCall tc = new ClienteCall();
		tc.show();
		

	}
}

// ----------------------------------------------------------------------------
// A classe Reader le a entrada do soquete e atualiza a OutputArea com as
// novas mensagens.
class Reader extends Thread {
	protected ClienteCall cliente;
	private TextArea OutputArea;

	public Reader(ClienteCall c, TextArea OutputArea) {
		super("chatclient Reader");
		this.cliente = c;
		this.OutputArea = OutputArea;
	}

	public void run() {
		DataInputStream in = null;
		String line;
		try {
			in = new DataInputStream(cliente.clisoc.getInputStream());
			while (true) {
				line = in.readLine();
				// Adiciona a nova mensagem a OutputArea
				OutputArea.appendText(line + "\r\n");
			}
		} catch (IOException e) {
			System.out.println("Reader:" + e);
		}
	}
}
F

Estou dando uma olhadinha.

Pergunta: o esquema de teclar ENTER quando a mensagem é digitada está funcionando pra vc?

flws

E

ESta sim normal

F

Oia eu aqui denovo.

Eu acho que a saida não será tão simples assim, a não ser que alguem tenha uma idéia melhor.

Vamos falar da situação atual:

  1. Vc tem um servidor socket que faz o seguinte:
    a)Toda vêz que um client se conecta ele cria um objeto que representa a “conexão” do client que acaba de se conectar; para constatar isso veja a classe Connection.
    b)Após a criação da conexão (Connection) ela é adicionada em uma lista que está montada da classe ChatServer; para constatr isso veja o código a seguir que está nesta classe.

synchronized(connections) { //adiciona esta nova conexao a lista connections.addElement(c); }
c)Toda vêz que uma mensagem é enviada por um client, o servidor percorre todas as conexões (ver item anterior) e envia a mensagem para cada cliente contido nesta lista; para verificar isto veja a classe ServerWriter no trecho de código a seguir:

outputline = outdata; synchronized (server.connections) { for (int i = 0; i < OutputStreams.size(); i++) { // Eh impressa a mensagem em cada um OutputStreams. PrintStream out; out = (PrintStream) OutputStreams.elementAt(i); out.println(outputline); } }

SUGESTÃO

a) Hoje a interface se conecta automaticamente, vc teria que fazer a interface (client) se conectar APÓS o usuário informar o NOME dele.

b) Quando o server receber a conexão vc tem que atribuir o nome do usuario ao objeto que representa a conexão (classe Connection).

c) Hoje a interface não permite que vc selecione o usuário que destino da mensagem, vc teria que ajustar isto com um ComboBox, Lista ou mesmo digitando.

d) A interface não tem uma lista dos usuários que já estão conectados, vc teria que incluir esta lista (para facilitar deveria ser a mesma lista mencionada no item anterior).

e) Para montar a lista de usuarios conectados (item c, d) você poderia utilizar o mesmo esquema que é utilizado pelo servidor para enviar as mensagens, ou seja, percorre a lista de conexões e envia o nome do maluco que acabou de se conectar.

f) Hoje após o envio da mensagem o servidor percorre a lista de conexões e envia a mensagem para todos os usuários, você teria que obter o usuário destino contido na mensagem e procura-lo na lista de conexões (ver item b) para enviar a mensagem ao usuario destino correto.

Espero ter ajudado e que vc não tenha deixado este trabalho para a ULTIMA HORA rsrsrsrsr.

flws

F

Oia eu aqui denovo.

Eu acho que a saida não será tão simples assim, a não ser que alguem tenha uma idéia melhor.

Vamos falar da situação atual:

  1. Vc tem um servidor socket que faz o seguinte:

a) Toda vêz que um client se conecta ele cria um objeto que representa a “conexão” do client que acaba de se conectar; para constatar isso veja a classe Connection.

b) Após a criação da conexão (Connection) ela é adicionada em uma lista que está montada da classe ChatServer; para constatr isso veja o código a seguir que está nesta classe.

synchronized(connections) { //adiciona esta nova conexao a lista connections.addElement(c); }

c) Toda vêz que uma mensagem é enviada por um client, o servidor percorre todas as conexões (ver item anterior) e envia a mensagem para cada cliente contido nesta lista; para verificar isto veja a classe ServerWriter no trecho de código a seguir:

outputline = outdata; synchronized (server.connections) { for (int i = 0; i < OutputStreams.size(); i++) { // Eh impressa a mensagem em cada um OutputStreams. PrintStream out; out = (PrintStream) OutputStreams.elementAt(i); out.println(outputline); } }

SUGESTÃO

a) Hoje a interface se conecta automaticamente, vc teria que fazer a interface (client) se conectar APÓS o usuário informar o NOME dele.

b) Quando o server receber a conexão vc tem que atribuir o nome do usuario ao objeto que representa a conexão (classe Connection).

c) Hoje a interface não permite que vc selecione o usuário que destino da mensagem, vc teria que ajustar isto com um ComboBox, Lista ou mesmo digitando.

d) A interface não tem uma lista dos usuários que já estão conectados, vc teria que incluir esta lista (para facilitar deveria ser a mesma lista mencionada no item anterior).

e) Para montar a lista de usuarios conectados (item c, d) você poderia utilizar o mesmo esquema que é utilizado pelo servidor para enviar as mensagens, ou seja, percorre a lista de conexões e envia o nome do maluco que acabou de se conectar.

f) Hoje após o envio da mensagem o servidor percorre a lista de conexões e envia a mensagem para todos os usuários, você teria que obter o usuário destino contido na mensagem e procura-lo na lista de conexões (ver item b) para enviar a mensagem ao usuario destino correto.

Espero ter ajudado e que vc não tenha deixado este trabalho para a ULTIMA HORA rsrsrsrsr.

flws

F

Desculpe a mensagem repetida, é que o site informou um erro no envio. :oops:

flws

E

Olá
Nossa quantas modificações
Mas não deixei para fazer de ultima hora
Teria como me ajudar nestas mudanças?

T

fantomas, implementei um chat nas aulas de java na faculdade uma vez e funcionava de um modo muito semelhante ao descrito acima.
O servidor tinha uma lista de conexões de clientes com os respectivos nomes, toda mensagem recebida era interpretada de quem ela vinha e enviada pros outros ou pra algum outro específico (o protocolo tinha tokens que indicavam se a msg era broadcast ou pra algum destinatário específico).
Sempre que alguém se conectava enviava o nome de usuário junto ao corpo de mensagem de conexão, o servidor registrava esse nome junto ao socket do cliente e enviava pra lista de todos os usuários a nova lista de nomes de usuários conectados.
Quando alguém era considerado inativo a thread de conexão dele (afinal, há uma thread pra cada conexão nova com listeners do socket) era retirada da lista de conexões e atualizava a lista de usuários pra todo mundo de novo.

Não deu tempo de implementar tudo do jeito que queria, ainda tava naquela de deixar pra última madrugada pré-entrega do projeto =Z prática hoje altamente não recomendada por mim (experiência própria).

Abraços.

E

Tchello
Teria como me ajudar fazer estas modificações ou dar alguns exemplos como posso fazer que não tenho muito noção.

T

Então, agora estou no trabalho mas assim que chegar em casa e tiver um tempo (lê-se la pras 20 hrs) posto aqui um pacote que fiz na época pra conexões TCP/IP via socket que já administrava todas as threads bonitinhas, sem que fosse necessário se preocupar com isso.
Embora haja mais o que se fazer.
Acredite, não é difícil fazer isso, é quebrando a cabeça que se vai conseguindo essas coisas.
Lembro-me bem dessa época, o quanto quebrei a cabeça pra entender como o diacho do socket funcionava (só desisti do datagram socket(udp) pq nao tive mais tempo e ateh hoje nao consegui fazer aquela bagaça rodar heheh).
Mas é questão de ter persistência e meter a cara sem medo de ser feliz. Acredite, funciona.

Abraços.

E

Sem problema Aguardo vc dar uma olhada .
Mas to quebrando tanto a cabeça q ta dificil , pois não tenho muita experiencia.
Mas se puder ajudar vou agradecer muito

F

Vc está utilizando qual IDE para implementar seus códigos?

Eclipse, NetBeans ou o que?

flws

E

Eclipse

H

Estava vendo o seu problema, e eu acho q devo ter alguma coisa na minha casa qd chegar eu vejo se encontro…

EDITADO PELA MODERAÇÃO

E

Olá HJ

Tomara q vc tenha alguma coisa que possa me ajudar.
Que ta dificil fazer.
Ai quem puder ajudar … agradeço

Obrigada

F

elisangela.bruno

Fiz algumas alterações no seu projeto:

a) Dividi ele em 2 packages, uma é o client e o outro o server, de modo que a estrutura ficou assim:

nomeDoProjeto\src
\client
\server
\Util

b) Fiz com que as classes ficassem em arquivos separados.

c) Fiz alguns ajustes na interface, nada demais, apenas inclui alguns objetos visuais.

Portanto quando receber esta mensagem vc, por favor, faça o seguinte:

1) Crie um novo projeto java no eclipse.
2) Clrie no SRC do projeto 2 packages um chamado CLIENT e o outro SERVER.
3) Copie as classes correspondente ao client para o package CLIENT.
4) Copie as classes correspondente ao server para o package SERVER.
5) Execute o server (classe ChatServer).
6) Execute o client (classe ClientCall).

Segue abaixo as classes do CLIENT:

package client;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ClientCall extends JFrame {

	public static final int DEFAULT_PORT = 4321;
	private Socket server;
	private Thread reader;
	public PrintStream outPut;

	// Criação dos objetos da tela
	private JLabel lblMiniChat = new JLabel("::.. MiniChat Conexão Socket ..::");
	private JLabel lblUsuario = new JLabel("Nome do usuario");
	private JButton btnLimpar = new JButton("Limpar");
	private JButton btnSair = new JButton("Sair");
	private JButton btnLogin = new JButton("Login");
	private JButton btnSend = new JButton("Enviar");
	private JTextField txtUsuario = new JTextField(15);
	private JTextField inputArea  = new JTextField(20);
	private JTextArea outputArea = new JTextArea(10, 45);
	private JComboBox cbxUsuarios = new JComboBox();
	
	public ClientCall() {
		this.initialize();
		this.connect();
	}
	
	private void connect() {
		try {
			// Cria um socket cliente passando o endereco e a porta do servidor
			this.server = new Socket("127.0.0.1", DEFAULT_PORT);
			this.reader = new Reader(this);
			this.outPut = new PrintStream(this.server.getOutputStream());
			this.reader.setPriority(3);
			this.reader.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void send(String msg) {
		this.outPut.println(msg);
	}
	
	public void addLogin(String user) {
		if( !user.equals(this.txtUsuario.getText())) {
			if( !this.userExists(user) ) {
				this.cbxUsuarios.addItem(user);
			}
		}
	}
	
	private boolean userExists(String user) {
		boolean exist = false;
		
		for(int i = 0; i < this.cbxUsuarios.getModel().getSize(); i++ ) {
			String u = (String)this.cbxUsuarios.getModel().getElementAt(i);
			if( u.equals(user)) {
				exist = true;
				break;
			}
		}
		
		return exist;
	}
	
	public Socket getServer() {
		return this.server;
	}
	
	public JTextArea getOutPutArea() {
		return this.outputArea;
	}
	
	private void initialize() {
		super.setTitle("::.. Comunicador Instântaneo ..::");
		super.setDefaultCloseOperation(EXIT_ON_CLOSE);

		super.setResizable(false);

		super.setLocationRelativeTo(null);

		Container janela = getContentPane();
		janela.setLayout(new FlowLayout());

		// Formatando Fonte
		this.outputArea.setFont(new Font("Serif", Font.ITALIC, 16));
		this.txtUsuario.setFont(new Font("Serif", Font.ITALIC, 16));
		
		// Adicionado componentes
		janela.add(this.lblMiniChat);
		janela.add(this.lblUsuario);
		janela.add(this.txtUsuario);
		janela.add(this.btnLogin);		
		janela.add(this.outputArea);
		janela.add(new Label("Digite a mensagem"));
		janela.add(this.inputArea);
		janela.add(this.cbxUsuarios);
		janela.add(this.btnSend);
		janela.add(this.btnLimpar);
		janela.add(this.btnSair);
		
		// Dimensões Janela
		super.setSize(550, 350);

		// Ações Botões
		this.btnLimpar.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				inputArea.setText("");
			}
			
		});
		
		this.btnLogin.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				send("LOGIN:"+txtUsuario.getText());
			}
			
		});
		
		this.btnSend.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				StringBuilder sb = new  StringBuilder(0);
				sb.append("FROM:");
				sb.append(txtUsuario.getText());
				sb.append(";");
				sb.append("TO:");
				sb.append((String)cbxUsuarios.getSelectedItem());
				sb.append(";");
				sb.append("MSG:");
				sb.append(inputArea.getText());
				send(sb.toString());
			}
			
		});
		
		this.btnSair.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
			
		});
	}

	public static void main(String[] args) {
		ClientCall tc = new ClientCall();
		tc.setVisible(true);
	}
}
package client;

import java.io.DataInputStream;
import java.io.IOException;

import util.Util;

//----------------------------------------------------------------------------
//A classe Reader le a entrada do soquete e atualiza a OutputArea com as
//novas mensagens.
class Reader extends Thread {
	protected ClientCall client;

	public Reader(ClientCall client) {
		super("chatclient Reader");
		this.client = client;
	}

	public void run() {
		DataInputStream in = null;
		String line;
		try {
			in = new DataInputStream(client.getServer().getInputStream());
			while (true) {
				line = in.readLine();

				String login = Util.getContent("LOGIN", line);

				if (login != null && login.length() != 0) {
					this.client.addLogin(login);
				} else {
					this.client.getOutPutArea().append(line+"\n");
				}
			}
		} catch (IOException e) {
			System.out.println("Reader:" + e);
		}
	}
}

Segue abaixo as classes do package SERVER:

package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.Vector;

public class ChatServer extends Thread
{
  int DEFAULT_PORT=4321;
  protected int port;
  protected ServerSocket server_port;
  protected ThreadGroup CurrentConnections;
  protected Vector connections;
  protected ServerWriter writer;
  private Calendar datatual;

  //Criar um ServerSocket
  public ChatServer()
  {
    super("Server");
    this.port=DEFAULT_PORT;
    try
    {
      server_port=new ServerSocket(port);
    }
    catch (IOException e)
    {
      System.err.println(e+"Exception");
    }
    //Cria um threadgroup para as conexoes
    CurrentConnections=new ThreadGroup("Server Connections");

    //Mensagem inicial na janela do servidor
    System.out.println("::.. Conexoes Realizadas ..::");

    //Um vetor para armazenar as conexoes
    connections=new Vector();
    writer=new ServerWriter(this);

    //Inicia o servidor para ouvindo as conexoes
    this.start();
  }

  public void run()
  {
    try
    {
      while(true)
      {
        datatual = Calendar.getInstance();
        Socket cliente_socket=server_port.accept();
        //Exibe na janela do servidor os clientes que conectam (mostra o host
        //do cliente, a porta e a data e hora da conexao 
        System.out.println("Host:"+cliente_socket.getInetAddress()+"³ Porta:"+
                            cliente_socket.getPort()+"³ "+datatual.getTime());
        Connection c=new Connection(cliente_socket,CurrentConnections,3,writer);
        //evita o acesso simultaneo
        synchronized(connections)
        {
          //adiciona esta nova conexao a lista
          connections.addElement(c);
        }
      }
    }
    catch(IOException e)
    {
      System.err.println(e+"Exception");
    }
  }

  //Inicia o servidor
  public static void main(String[] args)
  {
    new ChatServer();
  }
}
//----------------------------------------------------------------------------
package server;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;

import util.Util;

class Connection extends Thread {
	static int numberOfConnections = 0;
	protected Socket client;
	protected DataInputStream in;
	protected PrintStream out;
	protected ServerWriter writer;
	private String user = "";

	public Connection(Socket cliente_socket, ThreadGroup CurrentConnections, int priority, ServerWriter writer) {
		
		super(CurrentConnections, "Connection number" + numberOfConnections++);
		
		this.setPriority(priority);
		
		client = cliente_socket;
		
		this.writer = writer;
		
		try {
			// Atarraxa os streams aos streams de entrada e saida do socket do
			// cliente e adiciona este outputstream ao vetor que contem todos
			// os streams de saida, usados pelo escritor writer
			in = new DataInputStream(client.getInputStream());
			out = new PrintStream(client.getOutputStream());
			writer.outputStreams.addElement(out);
		} catch (IOException e) {
			try {
				client.close();
			} catch (IOException e2) {
				System.err.println("Exception while getting socket streams:" + e);
				return;
			}
		}
		// dispara Thread
		this.start();
	}
	
	public String getUser() {
		return this.user;
	}

	// O metodo run faz um laco lendo as mensagens recebidas
	public void run() {
		String inline;
		// Envia uma mensagem de boas vindas ao cliente
		out.println("Bem vindo ao Comunicador Instântaneo...");
		try {
			while (true) {
				// le uma linha de mensagem
				inline = in.readLine();
				// A conexao eh interrompida se null
				if (inline == null) {
					break;
				}
				
				String u = Util.getContent("LOGIN", inline);
				
				if( u != null && u.length() != 0) {
					this.user = u;
				}
				
				// Joga a linha no escritor writer
				writer.setOutdata(inline);
				synchronized (writer) {
					// chama o escritor synchronized() para evitar que duas
					// linhas
					// Connection o chamem ao mesmo tempo. Esta e uma forma de
					// "bloqueio".
					writer.notify();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				client.close();
			} catch (IOException e2) {
				e2.printStackTrace();
			}
		}
	}
}
package server;

import java.io.PrintStream;
import java.util.Vector;

import util.Util;

class ServerWriter extends Thread {
	protected ChatServer server;
	public Vector outputStreams;
	public String outdata;
	private String outputline;

	public ServerWriter(ChatServer s) {
		super(s.CurrentConnections, "Server Writer");
		server = s;
		outputStreams = new Vector();
		this.start();
	}

	public void setOutdata(String mensagem) {
		outdata = mensagem;
	}

	public synchronized void run() {
		while (true) {
			// A linha faz um laco para sempre, mas na vedade so e executada
			// quando
			// a condicao wait for reinicializada por um notify. Isso num bloco
			// sincronizado para bloquear a linha e evitar o acesso multiplo.
			try {
				this.wait();
			} catch (InterruptedException e) {
				System.out.println("Caught an Interrupted Exception");
			}
			outputline = outdata;

			String login = Util.getContent("LOGIN", outputline);
			String from = Util.getContent("FROM", outputline);
			String to = Util.getContent("TO", outputline);
			String msg = Util.getContent("MSG", outputline);

			synchronized (server.connections) {

				if (login != null) {
					for (int index = 0; index < outputStreams.size(); index++) {
						// Eh impressa a mensagem em cada um OutputStreams.
						PrintStream out = (PrintStream) outputStreams.elementAt(index);

						for (int idx = 0; idx < server.connections.size(); idx++) {
							Connection c = (Connection) server.connections.elementAt(idx);
							out.println("LOGIN:" + c.getUser());
						}
					}
				} else {
					for (int i = 0; i < server.connections.size(); i++) {
						Connection c = (Connection) server.connections.elementAt(i);

						if (c != null && c.getUser().equals(to)) {
							PrintStream out = (PrintStream) outputStreams.elementAt(i);
							out.println(from+" DIZ "+msg);
						}
					}
				}
			}
		}
	}
}

Segue abaixo a classe correspondente ao package UTIL:

package util;

public final class Util {
	public static String getContent(String tag, String msg) {
		String result = null;
		
		String[] parts = msg.split(";");
		
		for( String p : parts) {
			String[] tags = p.split(":");
			
			if(tags[0].equals(tag)) {
				result = tags[1];
				break;
			}
		}
		
		return result;
	}
}

flws

F

Constroi o projeto e faz alguns testes para ver se está funcionando pra você.

Fiz um pouco as pressas e não tive tempo de fazer um revisão.

Tentei não alterar demais o código, para não atrapalhar seu entendimento.

Espero te-la (caso vc não seja um FAKE) deixado “na cara do gol” com essas alterações.

flws

E

Fantomas

To fazendo as alterações para testar

Assim q terminar lhe aviso

Mas desde já agradeço a ajuda

E

Fantomas

era isso mesmo que precisava obrigada

tem alguns erros mas conserto

Valeu mesmo vc não imagina o quanto.

F

:smiley:

E

:smiley:

Agora vou começar a fazer um em outra linguagem q depois tenho q interagir duas linguagem …
Acho q ai vem a pior parte

E

Fontamas

Mais uma coisa sobre o envio das mensagens.
Quando envio as mensagens não fica na tela de quem mandou somente para o destino.
Gostaria de saber se existe a possibilidade de colocar para a origem tb as msg, ou ela pode sobrescrever ou perder os dados.

Aguardo

obrigada

F

Oi Elisangela,

Se entendi bem o que vc pediu, segue abaixo o código alterado.

Procure as linhas com “<–<<”, são 2 linhas, uma foi incluida e outra alterada.

package server;

import java.io.PrintStream;
import java.util.Vector;

import util.Util;

class ServerWriter extends Thread {
	protected ChatServer server;
	public Vector outputStreams;
	public String outdata;
	private String outputline;

	public ServerWriter(ChatServer s) {
		super(s.CurrentConnections, "Server Writer");
		server = s;
		outputStreams = new Vector();
		this.start();
	}

	public void setOutdata(String mensagem) {
		outdata = mensagem;
	}

	public synchronized void run() {
		while (true) {
			// A linha faz um laco para sempre, mas na vedade so e executada
			// quando
			// a condicao wait for reinicializada por um notify. Isso num bloco
			// sincronizado para bloquear a linha e evitar o acesso multiplo.
			try {
				this.wait();
			} catch (InterruptedException e) {
				System.out.println("Caught an Interrupted Exception");
			}
			outputline = outdata;

			String login = Util.getContent("LOGIN", outputline);
			String from = Util.getContent("FROM", outputline);
			String to = Util.getContent("TO", outputline);
			String msg = Util.getContent("MSG", outputline);

			synchronized (server.connections) {

				if (login != null) {
					for (int index = 0; index < outputStreams.size(); index++) {
						// Eh impressa a mensagem em cada um OutputStreams.
						PrintStream out = (PrintStream) outputStreams.elementAt(index);

						for (int idx = 0; idx < server.connections.size(); idx++) {
							Connection c = (Connection) server.connections.elementAt(idx);
							out.println("LOGIN:" + c.getUser());
						}
					}
				} else {
					for (int i = 0; i < server.connections.size(); i++) {
						Connection c = (Connection) server.connections.elementAt(i);

						String usuario = c.getUser(); // <--<< INCLUI ESTA LINHA
						
						if (c != null && (usuario.equals(to) || usuario.equals(from))) { // <--<< ALTEREI ESTA 
							PrintStream out = (PrintStream) outputStreams.elementAt(i);
							out.println(from+" DIZ "+msg);
						}
					}
				}
			}
		}
	}
}

flws

E

fantomas

E isso mesmo, mas ele ta conseguindo manda só uma mensagem as proximas estão dando erro.

F

No meu projeto está executando normalmente.

Que erro esta ocorrendo?

flws

E

Consegui fazer funcionar.

Obrigada

F

:smiley:

Vou preparar um explicação do código, para enviar; infelizmente o código que esta sendo utilizado, apesar de funcionar, ele não é muito didatico vamos dizer assim.

flws

E

E bem isso mesmo

Disse tudo na sua explicação.

Vou aguardar .
Obrigada

F

Oia eu aqui de novo,

Para entender o código vc dever ficar atenta (se vc não for uma FAKE) a dois detalhes bastante importantes:

OBS. Obser as setas indicativas que coloquei no código.

a) Este código que fica na classe ChatServer.

synchronized(connections)
        {
          //adiciona esta nova conexao a lista
          connections.addElement(c);    // <-------------------<< LINHA IMPORTANTE
        }

Toda vez que alguem se conecta (login) é incluido um objeto do tipo Connection em uma
lista ( connections )

b) Este código que fica na classe Connection.

try {
			in = new DataInputStream(client.getInputStream());
			out = new PrintStream(client.getOutputStream());
			writer.outputStreams.addElement(out); // <-------------------<< LINHA IMPORTANTE
		} catch (IOException e) {
			try {
				client.close();
			} catch (IOException e2) {
				System.err.println("Exception while getting socket streams:" + e);
				return;
			}
		}

Toda vez que um objeto do tipo Connection é criado o stream do socket que conecta o servidor ao cliente é incluido
em uma lista que está na classe ServerWriter.

Agora vamos falar do trafico das mensagens que ocorre na classe ServerWriter:

a) Toda mensagem que chega ela tem umas especies de “tags”, foi construida uma classe utilitaria
que informa qual o conteúdo correspondente a tal “tag”. A tag “FROM” por exemplo diz quem enviou
a mensagem.

String login = Util.getContent("LOGIN", outputline);
			String from = Util.getContent("FROM", outputline);
			String to = Util.getContent("TO", outputline);
			String msg = Util.getContent("MSG", outputline);

b) Se a tag login NÃO estiver vazia, quer dizer que alguem está efetuando uma operação de login,
logo a lista de streams e a lista de conexões são percorridas para que o ComboBox do Client
seja atualizado com o novo usuário. Aqueles que já estão conectados também são atualizados com
o usuário que acaba de ser incluido.

if (login != null) {
					for (int index = 0; index < outputStreams.size(); index++) {
						// Eh impressa a mensagem em cada um OutputStreams.
						PrintStream out = (PrintStream) outputStreams.elementAt(index); // <---<< Obtem o stream da lista.

						for (int idx = 0; idx < server.connections.size(); idx++) {
							Connection c = (Connection) server.connections.elementAt(idx); // <--<< Atualiza o stream do client com o usuário da conexão.
							out.println("LOGIN:" + c.getUser()); // <---<< INFORMA AOS CLIENTs QUE É UM LOGIN
						}
					}
				}

c) Quando o que chega no servidor não é um LOGIN, a lista de conexões é percorrida na intenção de localizar o usuário
destino da mensagem. Quando o usuário é encontrado, o stream correspondente é adquirido (outputStreams.elementAt(i)) e
utilizado para enviar a mensagem que acaba de chegar. Na versão inicial a lista de streams era percorrida e a mensagem
era enviada para todos os streams contidos na lista, ou seja, todos os usuários recebiam a mensagem.

for (int i = 0; i < server.connections.size(); i++) {
						Connection c = (Connection) server.connections.elementAt(i); // <----<< Linha importante

						String usuario = c.getUser(); 
						
						if (c != null && (usuario.equals(to) || usuario.equals(from))) {  // <----<< Linha importante
							PrintStream out = (PrintStream) outputStreams.elementAt(i); // <----<< Linha importante
							out.println(from+" DIZ "+msg);
						}
					}

Espero ter aumentado seu entendimento a respeito do código.

Aquele Java abraço pra você.

E

Fantomas

Agora deu para clarear bastante hehe

Q não sou uma experiente nisso hehe

Mas valeu pela grande ajuda.

:lol:
:wink:
Um Grande java abraço para vc tb

Criado 4 de março de 2009
Ultima resposta 6 de mar. de 2009
Respostas 36
Participantes 5