Sockets em java. Há Solução?

24 respostas
destructor

Bom dia pessoal,

Estou desenvolvendo uma aplicação em java que usa sockets, esta aplicação deve receber multiplas conexões, identifica-las e receber seus respectivos pacotes. Os pacotes que o aplicativo cliente envia é formado por 8 bytes, contudo o cliente pode enviar os 8 bytes de uma unica vez ou enviar pacotes quebrados tipo 2 bytes + 3 bytes + 3 bytes ou 3 bytes + 5 bytes.

Será que existe alguma maneira de garantir a recepção desse pacote por parte do aplicativo servidor em java ???

24 Respostas

nbluis

Como assim garantir a recepção dos pacotes???
Quem garante isso é o TCP.

Tu tem que ter uma logica para poder ler isso, mas se for toda essa comunicação no mesmo socket, dai fica facil… basta manter o buffer aberto e ler até que tenha chegado toda a informação…

Dica: Utiolize a API javax.nio para sockets, ele utiliza um conceito melhor para esta implementação…

destructor

nbluis,

vc fala fazer isso ??

in = socket.InputStream();

essa alternativa funciona bem para um cliente, mais se tiver por exemplo 20 ou 50 conectados ao servidor ??? no delphi consegui algo rezoavelmente bom, consigo indetificar as conexões e receber os pacotes quebrados com segurança, mais a aplicação vai rodar em linux não em windows.

A alternativa que estou pensado é usar threads, mais será que é seguro fazer isso ???

KWill

Uma alternativa para as Threads no caso de servidores de aplicações em rede com múltiplos clientes é o uso de Channels multiplexados.

Acho que esse pequeno exemplo deve servir:

import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class Server {
   private static int port = 9999;
   public static void main(String args[])
     throws Exception {
     Selector selector = Selector.open();

     ServerSocketChannel channel =
       ServerSocketChannel.open();
     channel.configureBlocking(false);
     InetSocketAddress isa = new InetSocketAddress(port);
     channel.socket().bind(isa);

     // Register interest in when connection
     channel.register(selector, SelectionKey.OP_ACCEPT);

     // Wait for something of interest to happen
     while (selector.select() &gt 0) {
       // Get set of ready objects
       Set readyKeys = selector.selectedKeys();
       Iterator readyItor = readyKeys.iterator();

       // Walk through set
       while (readyItor.hasNext()) {

         // Get key from set
         SelectionKey key =
           (SelectionKey)readyItor.next();

         // Remove current entry
         readyItor.remove();

         if (key.isAcceptable()) {
           // Get channel
           ServerSocketChannel keyChannel =
             (ServerSocketChannel)key.channel();

           // Get server socket
           ServerSocket serverSocket = keyChannel.socket();

           // Accept request
           Socket socket = serverSocket.accept();

           // Return canned message
           PrintWriter out = new PrintWriter
             (socket.getOutputStream(), true);
           out.println("Hello, NIO");
           out.close();
         } else {
           System.err.println("Ooops");
         }

       }
     }
     // Never ends
   }
}

Inté

nbluis

Cara, eu tenho trabalho muito em aplicações com sockets.

E todas elas são multithreads… tenho um bom retorno… sem problemas… sem contar que devem ser em média 5 clientes conectados simultaneamente o tempo todo… o servidor se vira bem …

valeu…

R

É, também trabalho mto com sockets, e o que fazemos é o seguinte:

instancio o ServerSocket e fico parado no accept. Quando meu servidor recebe uma conexão, o accept retorna um objeto socket. Passo esse objeto para uma outra thread para efeturar o processamento, e o meu servidor volta a escutar, independente do processamento da requisição.

Ou seja, recebo conexão, dou para outra classe processar e volto a escutar…

t+

destructor

rafael, tentei implementar da forma que comentou nesse código:

import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;


/**
 * Classe servidor para receber as conexões dos clientes
 */
public class Main implements Runnable {
    private int port;
    private ServerSocket serverSocket;
    private Socket socket;
    private InputStream in;
    private OutputStream out;
    private Thread currentThread;
    private byte[] buffRes = new byte[8];
    
    /** 
     * Método construtor da classe Main
     *
     * @param port identifica a porta de comunicação quer será usada pelo socket
     */
    public Main(int port) throws IOException {
        this.port = port;
        serverSocket = new ServerSocket(port);
        currentThread = new Thread(this);
        currentThread.start();        
    }
    
    /**
     * Método de execução implementado através da interface Runnable
     */
    public void run() {
        Thread thread = Thread.currentThread();
        while (currentThread == thread) {
            try {
                in = socket.getInputStream();
                /* Pega os pacotes enviados pela porta TCP/IP pela catraca */
                in.read(buffRes);
                /* Verifica o tamanho do pacote */
                if (buffRes.length >= 8) {
                    /* Processa o pacote enviado pelo cliente caso o mesmo
                       tenha 8 bytes.*/
                    //processCommand(buffRes);
                    System.out.println("Pacote recebido corretamente.");
                }
            } catch (IOException ex) {
                System.out.println(ex.getMessage().toString());
            } catch (Exception ex) {
                System.out.println(ex.getMessage().toString());
            }
        }
    }
    
    /** 
     * Método utilizado para para as threads em execução visto que o método
     * <code>stop()</code> esta deprecado.
     */
    public void stop() {
        currentThread = null;
    }
    
    /** Método main */
    public static void main(String[] args) {
        try {
            new Main(23);
        } catch (IOException ex) {
            System.out.println(ex.getMessage().toString());
        } catch (Exception ex) {
            System.out.println(ex.getMessage().toString());
        }
    }
    
}

só que agora tá dando o seguinte erro

Exception in thread Thread-0 java.lang.NullPointerException

at javaapplication6.Main.run(Main.java:64)

at java.lang.Thread.run(Thread.java:595)

sabe o que pode ser ?

Abdon

KWill esta solução com selector empilha as requisições e as trata tipo singlethread? Eu rodei este codigo em debug fazendo 5, 6 requisições e foi esta a impreção que eu tive! Este codigo ficaria bom para grande massa de acesso?

nbluis

Dentro desse sue código, qual a linha 64?

KWill

A intenção desse código é tratar tudo com singlethread mesmo, evitando ter que criar múltiplas threads, numa tentativa de poupar a máquina.

Como usa NIO, acho que deve ser mais rápido e/ou gastar menos recursos de máquina, mas para ter certeza (ou quase…) só fazendo berchmarks para testar.

Inté.

nbluis

Cara, não vejo ganho algum utilizando singleThread.

1 - Se tu tiver muitas conexões, um servidor SingleThread vai deixar tudo isso esperando… isso não é bom…

2 - Se tu tiver poucas Threads, não terá problema nenhum sobre processamento, threads não são tão custosas assim quanto a um servidor…

Minha Opinião…

Até…

KWill

Aproveitem para dar uma olhada neste artigo:

http://www.onjava.com/pub/a/onjava/2002/10/02/javanio.html?page=4

Deve ser esclarecedor para vocês, e não estou indicando a vocês que façam sempre monothread ou multithread, acho que é preciso dimensionar a solução de acordo com o tamanho do problema, no caso, o número de clientes conectados.

Inté.

destructor

pessoal, alguém saberia me dizer oq pode esta errado nesse código para o mesmo só funcionar qndo o cliente desconecta do servidor ??

public void run() {
        Thread thread = Thread.currentThread();
        while (currentThread == thread) {
            try {
                in = socket.getInputStream();
                out = socket.getOutputStream();
                in.read(buffRes);
                processCommand(buffRes);
                out.write(buffRes);
                
            } catch (IOException ex) {
                System.out.println(ex.getMessage().toString());
            } catch (Exception ex) {
                System.out.println(ex.getMessage().toString());
            }
        }
    }
nbluis

falta o flush();

Até…

destructor

e como uso o flush() no InputStream ??? não encontrei o metodo no netbeans

nbluis

O Flush é no outputstream.

valeu…

KWill

destructor:
e como uso o flush() no InputStream ??? não encontrei o metodo no netbeans

Você precisa usar flush() no OutputStream…

Inté.

ciczan

Cara, não é bem assim que o ServerSocket funciona. Você tem que usar o método Accept() para pegar o socket propriamente dito. Experimente colocar esta linha embaixo de serverSocket = new ServerSocket(port)

this.socket = serverSocket.accept();

Esta linha fica esperendo algum cliente conectar. Quando conecta ela retorna o socket da conexão. O que se faz é colocar isso dentro de um while e cada vez que um cliente conecta vc inicia uma nova Thread para tratar dele.

Te recomendo esse caminho, a não ser que vc vai tenha milhares de clientes. Eu já implemtentei um servidor com NIO não bloqueante para economizar Threads e no fim só deu confusão… começa simples…

ciczan

Aqui ta mais explicado: http://www.imasters.com.br/artigo/2385

destructor

então ciczan, o negocio é o seguinte. esse programa vai aceitar varias conexões, tipo 150 conexões certo dae estou tentando encontrar uma maneira de fazer isso, a unica que conheço em java é com threads mais estava fazendo um teste, exatamente isso que vc falou, e ele entra em loop despois que o cliente se desconecta.

estou quebrando a cabeça mesmo pra encontrar uma forma de fazer isso

ciczan

Vendo aquele codigo que vc postou achei que o critério de para não faz sentido:

while (currentThread == thread) {

Assim uma thread vai se acabar sempre que outra começar.

destructor

cara, essa é uma sugestão da propria Sun porque o metodo stop() aparece como deprecated no java 6 normalmente com o java 5 eu uso
o laço assim:

while (true) { ... }

estou tentando resolver o problema desta forma:

class TrataSocket extends Thread implements Runnable {
    private Socket socket;

    public TrataSocket(Runnable target, Socket socket) {
        /* aqui uso os parametros recebidos no construtor */
        super(target);
        this.socket = socket;
        start();
    }
    
    public void run() {
        /*  aqui coloco o processo pra tratar os dados enviados 
             pelo cliente */
        ...
    }

}
F

destructor:
e como uso o flush() no InputStream ??? não encontrei o metodo no netbeans

Nao faz sentido ter flush() no InputStream mesmo ja que tu nao envia dados e sim busca dados. No OutputStream sim faz sentido e ta la.

]['s

ViniGodoy

simplesmente faça out.flush()

Eu sugeriria que você lesse os oito bytes primeiro e depois trabalhasse com a decodificação do resultado.

Basicamente, isso pode ser resolvido num while mais ou menos como:

OutputStream out = Socket.getOutputStream();
int nRead = 0;
byte[] buffer = new byte[8];
while (out.read() != -1 && nRead &lt 8) {
   byte[nRead] = out.read();
   nRead++;
}

if (nLidos == 8) //Não será 8 se a conexão fechar. read() retornará -1.
    processMessage(buffer);

Usar Channels, Selectors e ByteBuffers é muito legal, aumenta muito o throughput e a performance do servidor, mas não creio que tenha sido a sua dúvida inicial. Se você está começando com sockets, eu sugeriria que você partisse para algo mais simples.

Se quiser mexer com NIO, comece com uma programação similar a com sockets, se beneficiando apenas do SocketChannel e dos ByteBuffers. O ByteBuffer facilita muito o trabalho com os buffers, suporta little e big endian e facilita a leitura de tipos primitivos.

Depois, quando você tiver mais prática e entender as vantagens/desvantagens do sistema multi thread, parta para os selectors.

benflodin

porra aqui no GUJ tem um artigo bom sobre socket:
http://guj.com.br/java.tutorial.artigo.126.1.guj

ve ai.

faz uma pesquisa que nao tem erro. pelo que voce explicou nao vejo necessidade de usar java.nio so vai te confundir. ao menos por enquanto.

Criado 23 de fevereiro de 2007
Ultima resposta 24 de fev. de 2007
Respostas 24
Participantes 9