Erro Sockets II , problemas com bytes + chat (Tópico grande)

Gente, estou com problemas com meu chat.
Assim, ele é bem grande, e eu fiquei com dúvidas sobre postar ou não no fórum, porque nao quero abusar da bondade.
Porém meus amigos nao souberam resolver.

E , pra falar a verdade, nao tenho pra quem pedir ajuda.
Estou estudando com livros do deitel na medida do possível.
Se eu estiver pedindo demais, me desculpe,ok?

O que ocorre com o chat é o seguinte :

As vezes ele funciona, as vezes não.

Quando não funciona :
O cliente começa a receber dados diferentes de tamanhos gigantes.Assim que inicia o servidor, a segunda mensagem vem gigante, e depois ele nao recebe mais nada.
O servidor aparentemente nao tem erros, ele funciona normalmente.

//
Quando Funciona :
O cliente recebe os dados.
Porém, pelo que eu testei com colega meu, que mora na Inglaterra, ele me disse que tinha vezes que ele digitava e nao aparecia na tela.
Só aparecia depois que eu respondia.

///Assim, são Muitas Classes Eu vou postar as que recebem e transmitem do cliente e do servidor, e no final eu coloco o link do projeto inteiro pra baixar, com todas as classes e o projeto do netbeans.
Queria que voces criticassem o máximo se puder, ok ?
:smiley:
Muito obrigado gente.


CLIENTE :

[code]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package Manager;

import CodeDecode.Receiver;
import CodeDecode.Transmitter;
import LogDebug.Bugs;
import View.ClientView;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*

  • @author André
    */
    public class Controller {

    public Bugs bugs = new Bugs();
    //
    public ClientView clientView;
    //
    private int PORT;
    private String HOST;
    public Socket socket;
    private String myUserName = “”;
    //
    public Thread threadReceiver;
    //
    public Receiver receiver;
    public Transmitter transmitter;

    public Controller(ClientView cv,String Host,int Port,String userName) {
    HOST = Host;
    PORT = Port;
    socket = setUpSocket(PORT, HOST);
    myUserName = userName;
    //
    clientView = cv;
    receiver = new Receiver(cv, socket);

     threadReceiver = new Thread(receiver);
     threadReceiver.start();
     
     transmitter = new Transmitter(socket);
     transmitter.sendMyUserName(userName);
    

    }

    public Controller() {
    PORT = 64500;
    HOST = “localhost”;
    socket = setUpSocket(PORT, HOST);
    transmitter = new Transmitter(socket);

     receiver = new Receiver(null, socket);
    
     threadReceiver = new Thread(receiver);
     threadReceiver.start();
    

    }

    public Socket setUpSocket(int Port, String Host) {
    try {
    socket = new Socket(Host, Port);
    } catch (UnknownHostException ex) {
    bugs.writeLog(ex.getMessage());
    System.out.println(ex.getMessage());
    } catch (IOException ex) {
    bugs.writeLog(ex.getMessage());
    System.out.println(ex.getMessage());
    }
    return socket;
    }
    }
    [/code]

[code]package CodeDecode;

import LogDebug.Bugs;
import View.ClientView;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**

  • @author André
    */
    public class Receiver implements Runnable {

    protected Socket socket;
    protected ClientView clientView;
    private boolean stop = false;

    //DEBUG:
    public Bugs bugs = new Bugs();

    public Receiver(ClientView view, Socket sock) {
    clientView = view;
    socket = sock;
    }

    @Override
    public void run() {

     try {
         while (true) {
             DataInputStream dis = new DataInputStream(socket.getInputStream());
    
             int tamanho = dis.readInt(); // Como é Read Int, acredito que ja leia 4 Bytes, correto?
             int tipoMensagem = dis.read(); // Tipo de mensagem
    
             System.out.println("Cliente*Tamanho DIS : " + tamanho);
             System.out.println("Cliente*TipoMensagem DIS : " + tipoMensagem);
    
             if (tipoMensagem == 0) {
                 String input = "";
                 for (int i = 1; i < tamanho; i = i + 2) {
                     input = input + dis.readChar();
                 }
                 sendMessageToView(input);
                 System.out.println("Mensagem : " + input);
             } else if (tipoMensagem == 1) {
                 System.out.println("È Um ArrayList! Decodificando ....");
                 String userList = decodeUserList(dis,tamanho);
                 System.out.println("Lista de usuários : " + userList);
                 //Enviar para Client View();
                 clientView.setListOfUsersToTable(userList);
    
             }
         }
     } catch (IOException e) {
         System.out.println("Error in Receiver Class!");
         bugs.writeLog(e.getMessage());
         e.printStackTrace();
        
     }
    

    }

    public String decodeUserList(DataInputStream dis,int tamanho)
    {
    String userList = “”;
    //
    try{

         String readUTF = dis.readUTF();
         userList = readUTF;
         
     }catch(Exception e)
     {
         System.out.println(e.getMessage());
         e.printStackTrace();
         bugs.writeLog(e.getMessage());
     }
     
    
     //
     return userList;
    

    }

    public boolean isStop() {
    return stop;
    }

    public void setStop(boolean stop) {
    this.stop = stop;
    }

    public void sendMessageToView(String input)
    {
    clientView.setReceivedMessageToView(input);
    }
    }
    [/code]

[code]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package CodeDecode;

import LogDebug.Bugs;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.Socket;

/**
*

  • @author André
    */
    public class Transmitter {

    private Socket socket;
    public Bugs bugs = new Bugs();

    public Transmitter(Socket sock) {
    socket = sock;
    }

    public void sendMessageToAll(String message) {
    try {

         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         DataOutputStream dos = new DataOutputStream(bos);
         dos.writeByte(0);
         dos.writeChars(message);
    
         byte[] msg = bos.toByteArray();
         DataOutputStream out = new DataOutputStream(socket.getOutputStream());
         out.writeInt(msg.length);
         out.write(msg);
         out.flush();
         System.out.println("Bytes Enviados");
    
     } catch (Exception e) {
         System.out.println("Tranmitter Class Error!");
         e.printStackTrace();
         bugs.writeLog(e.getMessage());
     }
    

    }

    public void sendMyUserName(String userName) {
    try {

         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         DataOutputStream dos = new DataOutputStream(bos);
         dos.writeByte(2); // Para enviar nickName ao Servidor:
         dos.writeUTF(userName);
    
         byte[] msg = bos.toByteArray();
         DataOutputStream out = new DataOutputStream(socket.getOutputStream());
         out.writeInt(msg.length);
         out.write(msg);
         out.flush();
         System.out.println("+ClienteTransmitter+Bytes Enviados");
     } catch (Exception e) {
         System.out.println(e.getMessage());
         e.printStackTrace();
         bugs.writeLog(e.getMessage());
     }
    

    }
    }
    [/code]

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
Servidor:
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

[code]package Manager;

import CodeDecode.Decoder;
import CodeDecode.Transmitter;
import ListaAuxs.Usuarios;
import View.ServerView;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

/**
*

  • @author André
    */
    public class MainController implements Runnable {

    public ServerView serverView;
    //
    public Transmitter transmitter;
    //
    public SocketAlive socketAlive;
    public Thread isSocketAlive = new Thread(socketAlive);
    //
    public SameSocketConnected sameSocketConnected = new SameSocketConnected(this);
    //
    public static int PORT;
    public ServerSocket serverSocket;
    //
    public ArrayList listaUsuarios = new ArrayList<>();
    //
    private boolean stopRunning = false;

    public MainController(ServerView view) {

         serverView = view;
         PORT = view.getPORT();
         socketAlive = new SocketAlive(this);
    

    }

    public void setViewLog(String info) {
    serverView.setServerLog(info);
    }

    @Override
    public void run() {
    try {
    serverSocket = new ServerSocket(PORT);
    System.out.println(“Server Opened!” + " In Port : " + PORT);
    setViewLog(“Server Opened!” + " In Port : " + PORT);

         //Verifica se os sockets estao not-Closed/OPEN
         isSocketAlive.start();
         
         while (stopRunning == false) {
             
          Socket socket = serverSocket.accept();
          //sameSocketConnected.sameSocketExists(socket);
             
          String clientInfo = ("Client Connected : " +  socket.getInetAddress().getHostName());    
             setViewLog(clientInfo);
                 System.out.println(clientInfo);
                 
                 //
                 Usuarios user = new Usuarios("UNKNOWN",socket);
                 listaUsuarios.add(user);
                 //
                 ///////
                 Decoder decoder = new Decoder(socket,this);
                 Thread decodingThread = new Thread(decoder);
                 decodingThread.start();
              
                 //{
                
                 //Envia A lista de Usuários On-Line para todos:
                 sendUserListToAll(listaUsuarios);
                 //}
                 
         }
         
         
     } catch (Exception e) {
         System.out.println("Error in MainController!");
         //e.printStackTrace();
     }
    

    }

    public void sendUserListToAll(ArrayList listaUsuarios)
    {
    Transmitter sendArrayList = new Transmitter(listaUsuarios);
    sendArrayList.sendUserArrayToAll();
    }

    public void sendToAll(String msg)
    {
    transmitter = new Transmitter(listaUsuarios);
    transmitter.sendMessageToAll(msg);
    }

    public void closeServerSocket()
    {
    try {
    serverSocket.close();
    } catch (IOException ex) {

     }
    

    }

    public boolean isStopRunning() {
    return stopRunning;
    }

    public void setStopRunning(boolean stopRunning) {
    this.stopRunning = stopRunning;
    }

}
[/code]

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

[code]package CodeDecode;

import ListaAuxs.Usuarios;
import Manager.MainController;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;

/**
*

  • @author André
    */
    public class Decoder implements Runnable {

    private Socket socket;
    public ArrayList listaUsuarios;
    public MainController mainController;

    public Decoder(Socket s, MainController mc) {
    mainController = mc;
    socket = s;
    }

    @Override
    public void run() {
    try {
    while (true) {
    DataInputStream dis = new DataInputStream(socket.getInputStream());

             int tamanho = dis.readInt(); // Como é Read Int, acredito que ja leia 4 Bytes, correto?
             int tipoMensagem = dis.read(); // Tipo de mensagem
    
             System.out.println("Tamanho do DIS : " + tamanho);
             System.out.println("Tipo Da Mensagem DIS : " + tipoMensagem);
    
             if (tipoMensagem == 0)// È uma Mensagem
             {
    
                 String MessageTypeZero = MessageTypeZero(dis, tamanho);
                 mainController.sendToAll(MessageTypeZero);
    
             } else if (tipoMensagem == 1) {
                 System.out.println("Servidor nao recebe arrays de usuarios");
             } else if (tipoMensagem == 2) {
                 String MessageTypeTwo = MessageTypeTwo(dis, tamanho);
                 
                 for(int i = 0; i < mainController.listaUsuarios.size(); i ++)
                 {
                     if(socket == mainController.listaUsuarios.get(i).getSocket())
                     {
                         mainController.listaUsuarios.get(i).setName(MessageTypeTwo);
                     }                 
                 }
                 mainController.sendUserListToAll(mainController.listaUsuarios);
             }
         }
     } catch (Exception e) {
         System.out.println("Error in Decoder Class!");
         e.printStackTrace();
     }
    

    }

    public String MessageTypeTwo(DataInputStream dis, int tamanho) throws IOException
    {
    System.out.println(“È um Username”);
    System.out.println(“Decodificando Username…”);

     String userName = "";
     
     userName = dis.readUTF();
     
     System.out.println("Username : " + userName);
     return userName;
    

    }

    public String MessageTypeZero(DataInputStream dis, int tamanho) throws IOException {

     System.out.println("È uma Mensagem!");
     System.out.println("DecodificandoMensagem...");
    
     String message = "";
    
     //Decodifica a Mensagem
     for (int i = 1; i < tamanho; i = i + 2) {
         message = message + dis.readChar();
     }
    
     System.out.println("Mensagem : \n" + message);
     return message;
    

    }
    }
    [/code]

¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨
¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨

[code]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package CodeDecode;

import ListaAuxs.Usuarios;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.ArrayList;

/**
*

  • @author André
    */
    public class Transmitter
    {
    public ArrayList listaUsuarios;

    public Transmitter(ArrayList lUsuarios)
    {
    listaUsuarios = lUsuarios;
    }

    public void sendUserArrayToAll()
    {
    Socket aux;
    Usuarios user;
    String todosUsuarios = “”;

     for(int k = 0; k < listaUsuarios.size();k++)
     {
         user = listaUsuarios.get(k);
         aux = user.getSocket();
         //todosUsuarios = todosUsuarios + "\n" + aux.getInetAddress().getHostAddress();
         todosUsuarios = todosUsuarios + "\n" + user.getName();
     }
    
     for (int i = 0; i < listaUsuarios.size(); i++) 
     {
         user = listaUsuarios.get(i);
         aux = user.getSocket();
         //
         codeAndSendArray(todosUsuarios , aux);
         //
     }
    

    }

    private void codeAndSendArray(String nome,Socket socket)
    {
    try{
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(bos);
    dos.writeByte(1); // Enviando lista de usuarios
    dos.writeUTF(nome);
    byte[] msg = bos.toByteArray();
    //
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    out.writeInt(msg.length);

         System.out.println("/Server/Tamanho do Array Sendo Enviado : " + msg.length);
         out.write(msg);
         out.flush();
         System.out.println("/Server/Bytes de Array Enviados para " + socket.getInetAddress().getHostName());
         
     }catch(Exception e)
     {
         System.out.println(e.getMessage());
         e.printStackTrace();
     }
    

    }

    public void sendMessageToAll(String message)
    {
    Socket aux;
    Usuarios user;

     for (int i = 0; i < listaUsuarios.size(); i++) 
     {
         user = listaUsuarios.get(i);
         aux = user.getSocket();
         codeAndSendString(message, aux);
     }  
    

    }

    private void codeAndSendString(String message,Socket socket)
    {
    try{
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(bos);
    dos.writeByte(0);
    dos.writeChars(message);
    byte[] msg = bos.toByteArray();

         DataOutputStream out = new DataOutputStream(socket.getOutputStream());
         out.writeInt(msg.length);
         System.out.println("/Server/Tamanho da mensagem Sendo Enviada : " + msg.length);
         out.write(msg);
         out.flush();
         System.out.println("/Server/Bytes Enviados para " + socket.getInetAddress().getHostName());
         
         
         
     }catch(Exception e)
     {
         System.out.println("Error in Transmitter Class!");
         e.printStackTrace();
     }
    

    }

}
[/code]

[code]package Manager;

import ListaAuxs.Usuarios;
import java.net.Socket;

/**
*

  • @author André Vinícius Lopes
    */
    public class SameSocketConnected {

    public MainController mainController;

    public SameSocketConnected(MainController mc)
    {
    mainController = mc;
    }

    public void sameSocketExists(Socket mySocket)
    {

     for(int i = 0;i < mainController.listaUsuarios.size();i++)
     {
         Usuarios usuarioList = mainController.listaUsuarios.get(i);
         System.out.println("SAME.SOCKET.EXISTS ::" + usuarioList.getNetAdress());
         if(usuarioList.getSocket() == mySocket)
         {
             System.out.println("Socket Already Exists, removing Old One...");
             mainController.listaUsuarios.remove(i);
         }
         
     }
    

    }

}
[/code]

[code]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package Manager;

import java.net.Socket;

/**
*

  • @author André Vinícius Lopes
    */
    public class SocketAlive implements Runnable {

    public MainController mainController;

    public SocketAlive(MainController mc) {
    mainController = mc;

    }

    @Override
    public void run()
    {
    while(true)
    {
    int index = 0;

        for(index = 0;index < mainController.listaUsuarios.size();index++)
        {
              Socket socket = mainController.listaUsuarios.get(index).getSocket();
            if(socket.isClosed())
            {
                mainController.listaUsuarios.remove(index);
                System.out.println("Removing Socket because is Closed : " +socket.getInetAddress().getHostAddress());
                
            }
        
        }
          
          
        
      }
    

    }
    }
    [/code]

Segue o LINK do Projeto:

https://www.dropbox.com/s/6ak8otyj1r2ygdd/ChatJavaII.7z

Nem vi o seu código direito, mas já vi que você não executou setTcpNoDelay (true) sobre o socket que você acabou de abrir - isso faz com que seja usado o algoritmo de Nagle (por favor, veja no Google o que é isso).

(Favor excluir da sua consulta ao Google eventuais hits para o ator Duda Nagle ou a jornalista Leda Nagle :slight_smile:

Obrigadão entanglement.Eu passei nas aulas de ISdocomp /assembly em falar nisso hahaha;

Sobre o chat:
Fiz isso, setTcpNoDelay(true);
Alterei no cliente e no servidor.

Nao estou conseguindo reproduzir o erro.// Isso é bom ^^

Bom, vou testar com uns colegas e ver.


Mais uma dúvida, esses meus métodos pra ver se o cliente fechou o programa e abriu de novo, nao esta funcionando.
Tipo, se eu abrir e fechar meu chat 3x, aparece que sao 3 usuários logados.
O que faço a respeito disso?

A resposta simples é “não é trivial saber se uma das pontas fechou o socket sem tentar escrever ou ler alguma coisa nele”.
É por causa disso que muitos protocolos de rede têm uma mensagem periódica (chamada normalmente “ping” ou “keep-alive”) que serve para ver se alguma das pontas se desconectou :slight_smile: . A idéia, como você deve saber, é que um dos lados mande uma mensagem de vez em quando (usualmente a cada 1 ou 5 segundos) para o outro lado, que deve respondê-la o mais rapidamente possível . Se o outro lado não responder, então você tenta mais algumas vezes até declarar que o outro lado caiu ou morreu :slight_smile:

Entanglement.

package Manager;

import java.net.Socket;

/**
 *
 * @author André Vinícius Lopes
 */
public class SocketAlive implements Runnable {

    public MainController mainController;

    public SocketAlive(MainController mc) {
        mainController = mc;

    }

    @Override
    public void run() 
    {
         while(true)
         {
           int index = 0;
            
           for(index = 0;index < mainController.listaUsuarios.size();index++)
           {
                 Socket socket = mainController.listaUsuarios.get(index).getSocket();
               if(socket.isClosed())
               {
                   mainController.listaUsuarios.remove(index);
                   System.out.println("Removing Socket because is Closed : " +socket.getInetAddress().getHostAddress());
                   
               }
           
           }
             
             
           
         }
    }
}

Então, minha classe responsável por isso esta assim.

Como eu poderia fazer?
Eu pensei Em fazer uma lista nessa classe de usuários que nao respondem ao ping.
Junto nesta lista, teria uma variável X , que se valer mais que 3, eu posso kikar o cara.

O que acha?

[quote=entanglement]A resposta simples é “não é trivial saber se uma das pontas fechou o socket sem tentar escrever ou ler alguma coisa nele”.
É por causa disso que muitos protocolos de rede têm uma mensagem periódica (chamada normalmente “ping” ou “keep-alive”) que serve para ver se alguma das pontas se desconectou :slight_smile: . A idéia, como você deve saber, é que um dos lados mande uma mensagem de vez em quando (usualmente a cada 1 ou 5 segundos) para o outro lado, que deve respondê-la o mais rapidamente possível . Se o outro lado não responder, então você tenta mais algumas vezes até declarar que o outro lado caiu ou morreu :slight_smile:

[/quote]

E se a pessoa voltar depos de fechar o aplicativo ?

Se a pessoa voltar, pega uma conexão nova. Simples assim :slight_smile:

Tem algum método pra ver se a conexão velha foi fechada sem ter que fazer ping ou algo do tipo?
Porque se eu tiver que fazer um método de transmissao no cliente e recepção no servidor , vou ter que re fazer o servidor.

[quote=entanglement]Nem vi o seu código direito, mas já vi que você não executou setTcpNoDelay (true) sobre o socket que você acabou de abrir - isso faz com que seja usado o algoritmo de Nagle (por favor, veja no Google o que é isso).

(Favor excluir da sua consulta ao Google eventuais hits para o ator Duda Nagle ou a jornalista Leda Nagle :)[/quote]

O problema ainda acontece.
Tem vezes que o cliente recebe uma mensagem em japônes e trava o socket.
Nao consegue receber mais nada.

Não entendo…

Tem algum método pra ver se a conexão velha foi fechada sem ter que fazer ping ou algo do tipo?
Porque se eu tiver que fazer um método de transmissao no cliente e recepção no servidor , vou ter que re fazer o servidor.
[/quote]

Pois é, você vai ter de refazer o servidor.

Tem algum método pra ver se a conexão velha foi fechada sem ter que fazer ping ou algo do tipo?
Porque se eu tiver que fazer um método de transmissao no cliente e recepção no servidor , vou ter que re fazer o servidor.
[/quote]

Pois é, você vai ter de refazer o servidor. [/quote]

Re-fiz. E aqueles erros começaram de novo.
Quando começa o cliente,as vezes ele ja recebe uma mensagem em japones e vários bytes sem nexo.