Dúvidas Básicas de Socket

É só criar regrinhas na sua String. Essas regrinhas são o tal do protocolo.

Por exemplo, vamos supor que você queira transmitir o nome de todos os participantes de uma conversa. Você poderia dizer que a mensagem que transmite isso começa com o texto “nomes:” seguido de todos os nomes separados por vírgula. Exemplo:

nomes: Bruno,Vinicius

Agora bastaria separar essa String usando split.

Vamos pegar um exemplo mais complexo. Agora o participante Vinicius quer mandar uma mensagem apenas para o Bruno, não para todos do chat. Você poderia definir que a expressão “cochichar para:” seria seguida do nome de quem irá receber a mensagem, seguido então da mensagem. Por exemplo:

cochichar para: Bruno: Olá bruno!

Perceba que para um sistema, haverá dezenas de mensagens como essas. O importante é que você pense no seu sistema e organize essas mensagens antes de começar a implementação do resto.
Aliás, se você lesse o tópico que linkei, veria que lá tem um exemplo de mensagem para montar uma lista de diretórios.

Ahh valeu Viny, nao tinha Visto aquele Link!!

Agora saquei.
Vou imprimir ele e ler com calma amanhã!

Mas tenho uma outra dúvida!!
Como que os programadores fazem com jogos? Por exemplo, enviar Tiles, Posições… etc?
È usado também essa lógica de protocolo? Ou algum outro tipo de lógica?

Sempre que se faz uma aplicação socket, especifica-se um protocolo.

No caso, eu prefiro usar protocolos binários.
Mas sim, existe uma mensagenzinha para cada informação que você queira transmitir via rede.

Eu não recomendo usar ObjectOutputStream ou ObjectInputStream.
É importante ter controle sobre o que é enviado em seu protocolo.

Essas classes podem até facilitar no início, mas se tornam um inferno de manutenção com o tempo.

[quote=ViniGodoy]Sempre que se faz uma aplicação socket, especifica-se um protocolo.

No caso, eu prefiro usar protocolos binários.
Mas sim, existe uma mensagenzinha para cada informação que você queira transmitir via rede.[/quote]

Ah oK!
Vou começar com esse então!
Ja imprimi aqui, e vou ler com calma amanhã :smiley:

Mais uma dúvida rsrs

Eu estou fazendo assim o projeto :

Enviar Mensagem :
"Enviar Mensagem : " + msg

O que esta entre aspas é o sinal de que é uma mensagem

//

Enviar Array :
"Lista de usuarios : " + list

Sendo que list é o objeto array

//

Esta ficando correto assim ?

Na verdade , mudei de idéia.
Vou usar o Byte mesmo…

Eu só nao entendi como fazer isso em código.

Vamo supor

Byte de Código = 0 .: Mensagem

no Projeto Cliente, em uma certa classe, seria assim!? :

[code]public ByteArrayOutputStream codificarMensagem(String mensagem)
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(0);
dos.writeChars(mensagem);
enviarMensagem(bos);
//return bos;
}

public void enviarMensagem(ByteArrayOutputStream mensagem)
{

byte[] msg = mensagem.getByteArray();
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.write.Int(msg.lenght);
out.write(msg.toByteArray());
out.flush();
}

[/code]

Assim mesmo ?

Ahh, mais uma pergunta.
Fiquei lendo o Tutorial do Viny, várias vezes. Imprimi, grifei.E até consegui implementar pra enviar.
MAS,
como devo fazer pra ler?

Tipo :

if( primeiroByte == 0)
{
lermensagem();
} else if …

Como que eu faço isso???

no Projeto Cliente, em uma certa classe, seria assim!?

Isso mesmo.

E para ler:

int primeiroByte = dataInputStream.read(); //Lê um byte if (primeiroByte == 0) { //Faz qualquer coisa }

[quote=ViniGodoy]no Projeto Cliente, em uma certa classe, seria assim!?

Isso mesmo.

E para ler:

int primeiroByte = dataInputStream.read(); //Lê um byte if (primeiroByte == 0) { //Faz qualquer coisa }[/quote]

Ficou Assim!!
Agora como leio a mensagem? o readLine esta deprecado e nao tem hasNext();

[code] @Override
public void run() {

    try {
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        int read = dis.read();
        
            if (read == 0)// È uma Mensagem
            {
        
            }

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

}[/code]

Você lê usando os métodos readByte(), readInt(), etc… na mesma ordem que você gravou, você lè.

Em protocolos binários, não existe mais o conceito de “linhas”. Esqueça isso, os dados estão lado-a-lado, basta lê-los na mesma ordem que você gravou.

[quote=ViniGodoy]Você lê usando os métodos readByte(), readInt(), etc… na mesma ordem que você gravou, você lè.

Em protocolos binários, não existe mais o conceito de “linhas”. Esqueça isso, os dados estão lado-a-lado, basta lê-los na mesma ordem que você gravou.[/quote]

Assim Viny?

@Override
    public void run() {

        try {
            DataInputStream dis = new DataInputStream(socket.getInputStream());
            int read = dis.read();
            
                if (read == 0)// È uma Mensagem
                {
                    String input = dis.readUTF();
                }

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

    }

Isso mesmo.
Se a sua mensagem 0 tiver um UTF-8 no início, é assim mesmo.

[quote=ViniGodoy]Isso mesmo.
Se a sua mensagem 0 tiver um UTF-8 no início, é assim mesmo.[/quote]

Eu não sei se ela tem UTF-8 no inicio…

Meu transmissor de mensagem 0 esta assim :

[code]public void codificarMensagemEtransmitir(String mensagem) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(0);
dos.writeChars(mensagem);
enviarMensagem(bos);
} catch (Exception e) {
e.printStackTrace();
}
}

public void enviarMensagem(ByteArrayOutputStream mensagem) throws IOException {

    byte[] msg = mensagem.toByteArray();
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    out.writeInt(msg.length);
    out.write(msg);
    out.flush();
    System.out.println("Bytes Enviados");
}[/code]

Como que devo ler??? aaaa que confusão

Veja a mensagem que você montou:
a) Um INT contendo o tamanho do pacote;
b) Um BYTE contendo o número 0 (que pode ser o ID da mensagem);
c) Caracteres até o final da mensagem.

Como vc deve ler:
a) Leia o INT;
b) Leia a quantidade de bytes que esse int indica, gravando num buffer;
c) Leia desse buffer o primeiro byte. Isso indica o tipo da mensagem.
d) No caso da mensagem 0, leia os demais bytes para dentro de uma String.

Os passos a e b podem estar numa função separada, para todas as mensagens do seu protocolo.

[quote=ViniGodoy]Veja a mensagem que você montou:
a) Um INT contendo o tamanho do pacote;
b) Um BYTE contendo o número 0 (que pode ser o ID da mensagem);
c) Caracteres até o final da mensagem.

Como vc deve ler:
a) Leia o INT;
b) Leia a quantidade de bytes que esse int indica, gravando num buffer;
c) Leia desse buffer o primeiro byte. Isso indica o tipo da mensagem.
d) No caso da mensagem 0, leia os demais bytes para dentro de uma String.

Os passos a e b podem estar numa função separada, para todas as mensagens do seu protocolo.[/quote]

Obrigadão Viny, mas ainda tenho dúvidas…
a) e d) não são dificeis mas o b) e C) nao tenho a mínima noção de como fazer >.<

Como vou saber quantos bytes dizem o tamanho do pacote?
Tipo, la dentro vai estar 010101010101010000000000000000000000011111111111

O Tamanho pode ser praticamente qualquer numero.
E em que tipo de Buffer Devo Guardar?

E como vou transformar só uma parte em String???

[quote=Andre Lopes][quote=ViniGodoy]Veja a mensagem que você montou:
a) Um INT contendo o tamanho do pacote;
b) Um BYTE contendo o número 0 (que pode ser o ID da mensagem);
c) Caracteres até o final da mensagem.

Como vc deve ler:
a) Leia o INT;
b) Leia a quantidade de bytes que esse int indica, gravando num buffer;
c) Leia desse buffer o primeiro byte. Isso indica o tipo da mensagem.
d) No caso da mensagem 0, leia os demais bytes para dentro de uma String.

Os passos a e b podem estar numa função separada, para todas as mensagens do seu protocolo.[/quote]

Obrigadão Viny, mas ainda tenho dúvidas…
a) e d) não são dificeis mas o b) e C) nao tenho a mínima noção de como fazer >.<

Como vou saber quantos bytes dizem o tamanho do pacote?
Tipo, la dentro vai estar 010101010101010000000000000000000000011111111111

O Tamanho pode ser praticamente qualquer numero.
E em que tipo de Buffer Devo Guardar?

E como vou transformar só uma parte em String???
[/quote]

Ahh , espera!
È só um byte que diz o tamanho? Se for isso… então é Total de Bytes - 2 , que devem ser lidos ?

[quote=Andre Lopes][quote=Andre Lopes][quote=ViniGodoy]Veja a mensagem que você montou:
a) Um INT contendo o tamanho do pacote;
b) Um BYTE contendo o número 0 (que pode ser o ID da mensagem);
c) Caracteres até o final da mensagem.

Como vc deve ler:
a) Leia o INT;
b) Leia a quantidade de bytes que esse int indica, gravando num buffer;
c) Leia desse buffer o primeiro byte. Isso indica o tipo da mensagem.
d) No caso da mensagem 0, leia os demais bytes para dentro de uma String.

Os passos a e b podem estar numa função separada, para todas as mensagens do seu protocolo.[/quote]

Obrigadão Viny, mas ainda tenho dúvidas…
a) e d) não são dificeis mas o b) e C) nao tenho a mínima noção de como fazer >.<

Como vou saber quantos bytes dizem o tamanho do pacote?
Tipo, la dentro vai estar 010101010101010000000000000000000000011111111111

O Tamanho pode ser praticamente qualquer numero.
E em que tipo de Buffer Devo Guardar?

E como vou transformar só uma parte em String???
[/quote]

Ahh , espera!
È só um byte que diz o tamanho? Se for isso… então é Total de Bytes - 2 , que devem ser lidos ? [/quote]

Tentei isso aqui, nao deu certo :stuck_out_tongue:

[code] @Override
public void run() {

    try {
        DataInputStream dis = new DataInputStream(socket.getInputStream());
        int read = dis.read();

        if (read == 0)// È uma Mensagem
        {
            String input = &quot;oi&quot;;
            for (int i = 0; i &lt; dis.readInt(); i++) {
                input = input + dis.read();
            }
            
            System.out.println(&quot;&quot; + input);
        }
        
        

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

Você vai saber o tamanho pq foi você que escreveu os bytes lá.

No seu protocolo, sua mensagem COMEÇA com um int, contendo o tamanho da mensagem. Pelo menos, é o que o método sendMessage faz.

Então, seu PRIMEIRO comando tem que ser um readInt:

int tamanho = dis.readInt(); //Lê o tamanho da mensagem.

Em seguida, você pode criar um buffer, e fazer a leitura do pacote todo para lá. O processo é um pouco mais trabalhoso do que parece, já que num socket, você nunca sabe quantos bytes virão exatamente a cada leitura. Precisa fazer um for.

No início do bloco desses bytes lidos, virá o identificador da mensagem. Que tem um único byte de tamanho.
Depois disso, os chars da mesagem.

Como você sabe o número de bytes? Estudando a documentação:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Observe que ele fala quantos bits (portanto, quantos bytes) ocupa na memória cada tipo de dado. Em resumo:
1 long = 8 bytes
1 int = 4 bytes
1 short = 2 bytes
1 byte = 1 byte
1 float = 4 bytes
1 double = 8 bytes
1 String = varia. Por isso geralmente vamos transmitir o tamanho da String antes, ou um terminador, como o \n.

Sem entender como os dados são codificados, é difícil escrever um protocolo, ou mesmo um programa para gravar e ler um arquivo binário.

Mais importante do que isso, se você for estudar como comunicar uma aplicação Windows com um Mac, você teria que saber não só quantos bytes os dados ocupam em cada plataforma, mas também a ordem que eles são gravados na memória do computador (que pode ser little ou big endian).

Pode parecer complicado mas, após vencer a teoria básica, você vai ver que é mais simples do que ficar fazendo parse de arquivos texto. Pois os dados já estão lá. Se você enviar um dado gravado assim:

out.writeByte(MSG_ID); out.writeInteger(usuario.id); out.writeFloat(usuario.salario);

Vai ler assim:

int id = out.readByte(); if (msg == MSG_SALARIO) { usuario.setId(in.readInteger()); usuario.setSalario(in.readFloat()); }

Acho que entendi.
Então eu escrevi o tamanho em 4 bytes porque é Int!
Em seguida eu escrevi mais 4 bytes dizendo o tipo da mensagem?
Eu uso esses 4 bytes do tamanho e guardo em um int. Esse int sera o meu limite do for.

Lerei tantos bytes o limite disser.


Acertei ? :smiley:


Obrigadão Viny, deve ter dado trabalho escrever tudo isso.
Estou até Imprimindo pra deixar guardado numa pasta que eu tenho o.o

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.