Dúvidas Básicas de Socket

[quote=ViniGodoy]Você começou, de cara, escrevendo um int (4 bytes) cujo conteúdo era o tamanho da mensagem.

E, sim, esse valor você vai usar no seu for.[/quote]

Alguma Coisa esta faltando rsrs.
Mas acho que ja melhorou :

[code]@Override
public void run() {

    try {
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        
        int tamanho = dis.readInt(); // Como é Read Int, acredito que ja leia 4 Bytes, correto?
        int tipoMensagem = dis.readInt(); // Tipo de mensagem
        
        if (tipoMensagem == 0)// È uma Mensagem
        {
            String input = "";
            
            for (int i = 0; i < tamanho; i++) {
                input = input + dis.read();
            }
            
            System.out.println("" + input);
        }
        
        

    } catch (Exception e) {
        System.out.println(e.getMessage());
        //e.printStackTrace();
    }

}[/code]

Agora esta quase funcionando VinY!

[code]@Override
public void run() {

    try {
        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);
        System.out.println(tipoMensagem);
        
        if (tipoMensagem == 0)// È uma Mensagem
        {
            String input = "";
            
            for (int i = 0; i < tamanho; i++) {
                input = input + dis.readChar();
                //System.out.println("" + input); // Esta linha imprime aos poucos, certinho.... Mas 
            }
            
            System.out.println("" + input); // Esta debaixo imprime null -.-
        }
        
        

    } catch (Exception e) {
        System.out.println(e.getMessage());
        //e.printStackTrace();
    }

}[/code]

Já rodou com o depurador para ver quando a String ficou null?

Uma coisa, seu i provavelmente não irá começar em 0, e sim em 1. Isso porque um byte já foi lido no tipo da mensagem.

[quote=ViniGodoy]Já rodou com o depurador para ver quando a String ficou null?

Uma coisa, seu i provavelmente não irá começar em 0, e sim em 1. Isso porque um byte já foi lido no tipo da mensagem.[/quote]

Fiz isso e ainda imprime null.
Tentei ir subtraindo os bytes, mas nao consegui , até que…
Somei as linhas do for, antes de dar null;… Que são 14 e deu certo.

Mas nao estou entendendo o porque disso…

[code] @Override
public void run() {

    try {
        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);
        System.out.println(tipoMensagem);
        
        String input = &quot;!*&quot;;
        if (tipoMensagem == 0)// È uma Mensagem
        {
           
            //Troquei 'tamanho' por 14 e Funcionou
            for (int i = 1; i &lt; 14; i++) {
                input = input + dis.readChar();
                System.out.println(&quot;&quot; + input); // Esta linha imprime aos poucos, certinho.... Mas 
            }
            
            System.out.println(&quot;Total : &quot; + input); // Esta debaixo imprime null -.-
        }
        
        

    } catch (Exception e) {
        System.out.println(e.getMessage());
        //e.printStackTrace();
    }

}[/code]

run: Server Opened... Client Connected : 127.0.0.1 29 0 !*O !*Ol !*Ola !*Ola !*Ola B !*Ola By !*Ola Byt !*Ola Byte !*Ola ByteA !*Ola ByteAr !*Ola ByteArr !*Ola ByteArra !*Ola ByteArray Total : !*Ola ByteArray

Ué? Onde está o null? Ali está escrito:
Total !*Olá ByteArray.

[quote=ViniGodoy]Ué? Onde está o null? Ali está escrito:
Total !*Olá ByteArray.[/quote]
Então, foi porque eu troquei a variável ‘tamanho’ do for, para 14;

Aí ele Faz certo.
Mas se eu colocar Tamanho ou Tamanho -5 , ele imprime null !!

Sua confusão também está no fato de um char conter 2 bytes, não um só.

Então no for, ao invés de i++, você vai fazer i+=2;

E note que vai ficar certinho. Seu tamanho começa com 29. O i vai de 1 até 29, pulando de 2 em 2, ou seja, vc vai ler (29-1=28/2 = 14 caracteres).

[quote=ViniGodoy]Sua confusão também está no fato de um char conter 2 bytes, não um só.

Então no for, ao invés de i++, você vai fazer i+=2;

E note que vai ficar certinho. Seu tamanho começa com 29. O i vai de 1 até 29, pulando de 2 em 2, ou seja, vc vai ler (29-1=28/2 = 14 caracteres).[/quote]

aff è verdade. ASCII

LOL como sou estúpido. Pior que fiquei aqui tentando achar a lógica… haha, que chatO isso.

Eu posso tambem fazer tamanho/2 ?

Ahh , i+=2 é a mesma coisa que i = i +2 , não é ?

Obrigadão VinY!

hahaha
Agora Funcionou!!!

run: Server Opened... Client Connected : 127.0.0.1 29 0 Total : !*Ola ByteArray!

Pior que eu Dormi pensando no que eu estava errando no input !!

[code]
@Override
public void run() {

    try {
        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);
        System.out.println(tipoMensagem);
        
        String input = "!*";
        if (tipoMensagem == 0)// È uma Mensagem
        {
           
            //Troquei 'tamanho' por 14 e Funcionou
            for (int i = 1; i <tamanho;i=i+2) {
                input = input + dis.readChar();
                //System.out.println("" + input); // Esta linha imprime aos poucos, certinho.... Mas 
            }
            
            System.out.println("Total : " + input); // Esta debaixo imprime null -.-
        }
        
        

    } catch (Exception e) {
        System.out.println(e.getMessage());
        //e.printStackTrace();
    }

}[/code]

Então, com o tempo vc cria métodos utilitários para facilitar o trabalho. Eu, por exemplo, costumo a mandar um int com o tamanho da String antes de todas as Strings. Mas daí, já mando o tamanho em caracteres (o size() da String). Isso facilita muito a leitura. E já crio um método readString na minha classe para ler o int seguido dos chars e retornar a String direto:

public String readString(DataInputStream in) { int tamanho = in.nextInt(); StringBuilder out = new StringBuilder(tamanho); for (int i = 0; i &lt; tamanho; i++) { out.append(in.readChar()); } return out.toString(); }

Mas claro, isso porque em meus protocolos, eu sempre incluo o tamanho da String antes do texto. Outra possibilidade é fazer um método que leia até um terminador, por exemplo, o \0 (isso é útil se você estiver comunicando com C - onde no caso, cada caracter é ASCII e não unicode e só ocupa 1 byte):

public String readCString(DataInputStream in) { int tamanho = in.nextInt(); StringBuilder out = new StringBuilder(); char ch = (char)in.nextByte(); while (ch != '\0') { out.append(ch); ch = (char)in.nextByte(); } return out.toString(); }

[quote=ViniGodoy]Então, com o tempo vc cria métodos utilitários para facilitar o trabalho. Eu, por exemplo, costumo a mandar um int com o tamanho da String antes de todas as Strings. Mas daí, já mando o tamanho em caracteres (o size() da String). Isso facilita muito a leitura. E já crio um método readString na minha classe para ler o int seguido dos chars e retornar a String direto:

public String readString(DataInputStream in) { int tamanho = in.nextInt(); StringBuilder out = new StringBuilder(tamanho); for (int i = 0; i &lt; tamanho; i++) { out.append(in.readChar()); } return out.toString(); }

Mas claro, isso porque em meus protocolos, eu sempre incluo o tamanho da String antes do texto. Outra possibilidade é fazer um método que leia até um terminador, por exemplo, o \0 (isso é útil se você estiver comunicando com C - onde no caso, cada caracter é ASCII e não unicode e só ocupa 1 byte):

public String readCString(DataInputStream in) { int tamanho = in.nextInt(); StringBuilder out = new StringBuilder(); char ch = (char)in.nextByte(); while (ch != '\0') { out.append(ch); ch = (char)in.nextByte(); } return out.toString(); }
[/quote]

Verdade, java usa unicode…
Mas achei que ascII também usava 8 bits - 2 bytes

Viny, posso tirar mais uma dúvida ??
Estou serializando o arrayList, mas eu devo enviar como Object Output ou byte Output???

// public void encodeAndSendUsersList(ArrayList<Usuarios> listUsers)


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

import AuxManager.Usuarios;
import Manager.InitializeServer;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
import java.io.Serializable;

/**
 *
 * @author André
 */
public class ServerMessenger implements Runnable {

    private Socket socket;
    public ArrayList&lt;Usuarios&gt; listaUsuarios;
    public InitializeServer main;

    public ServerMessenger(Socket s, InitializeServer m) {
        socket = s;
        main = m;

        Usuarios usuario = new Usuarios(&quot;&quot; + socket.getInetAddress().getHostName(), socket, &quot;&quot; + socket.getInetAddress());
        main.listaUsuarios.add(usuario);

    }

    @Override
    public void run() {

        try {
            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);
            System.out.println(tipoMensagem);


            if (tipoMensagem == 0)// È uma Mensagem
            {
                String input = socket.getInetAddress() + &quot;Said : &quot;;
                for (int i = 1; i &lt; tamanho; i = i + 2) {
                    input = input + dis.readChar();
                    //System.out.println(&quot;&quot; + input); 
                }
                decodeMessage(input);

            }



        } catch (Exception e) {
            System.out.println(e.getMessage());
            //e.printStackTrace();
        }

    }

    public void decodeMessage(String input) {
        try {

            //Devolve a Informação que o usuário digitou, para todos os clientes 
            for (int i = 0; i &lt; main.listaUsuarios.size(); i++) {
                Socket aux = main.listaUsuarios.get(i).getSocket();
                PrintWriter pwAux = new PrintWriter(aux.getOutputStream());

                pwAux.println(input);
                pwAux.flush();
            }//Fim da Devolução de Informação
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public void encodeAndSendUsersList(ArrayList&lt;Usuarios&gt; listUsers) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //DataOutputStream dos = new DataOutputStream(bos);
            //dos.writeByte(1);//1 == Array List!!!
            
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeByte(1);
            oos.writeObject(listUsers);
            
            
            
            
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

Eu sempre uso o DataOutputStream e DataInputStream para tudo. Dá mais trabalho, mas você tem mais controle sobre o protocolo. E, como você deve ter percebido, o protocolo é um fator bastante crítico em qualquer aplicação socket.

Hmm, mas ele nao tem Write(Object)

aa não ser que eu use toString();
Posso fazer isso ?

Você escreve campo por campo. E lê campo por campo…

Então em vez de eu mandar o array, eu mando as Strings que estao dentro do array?? Hmm, vou fazer isso

Isso. Vamos supor que você tenha um array de 10 Strings. Eu geralmente organizaria meu protocolo para enviar assim:
a) A quantidade de elementos do array (int)
Para cada String no array
b) O tamanho da String em caracteres (int)
c) O texto da String;

Assim fica fácil na hora de fazer a leitura.

[quote=ViniGodoy]Isso. Vamos supor que você tenha um array de 10 Strings. Eu geralmente organizaria meu protocolo para enviar assim:
a) A quantidade de elementos do array (int)
Para cada String no array
b) O tamanho da String em caracteres (int)
c) O texto da String;

Assim fica fácil na hora de fazer a leitura.[/quote]

Legal, agora consigo fazer !!
Só uma dúvida, na hora que eu lia os chars, eu lia 2 bytes/char

Agora pra ler, vou ter que fazer parse em , por exemplo, cada “,” , e em seguida guardo cada valor entre “,” em algum lugar, por exemplo em um outro array.

Consigo sim!, Vou fazer e ja posto aqui rsrsr

Em termos de código, esse exemplo ficaria:

Escrevendo:

out.writeInt(nomes.size()); for (String nome : nomes) { out.writeInt(nome.size()); out.writeChars(nome.toCharArray()); }

Lendo:

int tamanhoArray = in.readInt(); List&lt;String&gt; nomes = new ArrayList&lt;String&gt;(); for (int i = 0; i &lt; tamanhoArray; i++) { nomes.add(readString(in)); }

Sendo readString o método que descrevi no post anterior. :wink:

PS: Aquele writeInt e writeChars provavelmente eu transformaria num método chamado writeString.

Só confirmando: 1 byte = 8 bits.
1 char ascii = 1 byte - por isso existem 256 caracteres possíveis
1 char java = 2 bytes;

Observe que num protocolo binário não há separadores. Eu simplesmente escrevi as Strings e valores inteiros seguidos, um do lado do outro. Você organiza a escrita de modo a permitir a leitura posterior.