Newsgroup: it.comp.java
Titolo: Java Socket e deadlock...

Salve, ho imparato java da poco, e sto cimentandomi nell'utilizzo delle
socket per un programma client/server.
Il tutto funzionava quando utilizzavo DataInputStream e DataOutputStream,
poi ho deciso di cambiarli con i metodi BufferedReader e BufferedWriter,
che scrivono semplici stringhe di testo e non oggetti java.
Il problema è il seguente, il server parte, resta in attesa di connessioni,
appena arriva una richiesta da un client crea un thread (classe Request)
che si occuperà della richiesta.
Il thread resta in attesa della stringa "Hello Server" e risponde con "Hello
Client" dopo di che entra in un loop nel quale dovrà interpretare ed
eseguire i vari comandi dal client.
Ripeto, quando utizzavo i metodi DataInput/OutputStream funzionava alla
perfezione, ora il client si blocca su "Hello Server" e al server non
arriva alcuna richiesta, fin quando non chiudo il client, in pratica è come
se il buffer non fosse scritto del tutto, nonostante io abbia fatto uso del
metodo flush() dopo ogni scrittura.
Vi posto alcuni frammenti di codice:
QUESTA E' LA CLASSE SERVER CHE CREA I THREADS "REQUEST"



QUESTA E' UN FRAMMENTO DELLA CLASSE SERVER CHE CREA I THREADS "REQUEST"
    /**
     * Attende connessioni dal client
     * 
     * @param server è la socket utilizzata per la connessione
     */
    private void listen(ServerSocket server) {
 
logger.info
("In attesa di una richiesta client");
        try {
            // ciclo infinito
            while (true) {
                // attende una connessione da un client
                Socket client = server.accept();
                // quando viene stabilita la connessione viene creata una
socket
 
                /* aquisisce il lock sull'oggetto logger, infatti
                 * potrebbero esserci più threads che tentano di
                 * loggare qualcosa nello stesso momento.
                 */
                synchronized(logger) {
                    // stampa l'informazione nel log
 
logger.info
("Richiesta di connessione da: " +
client.getInetAddress());
                }
                /* fa partire un nuovo thread che è un'istanza
                 * della classe Request, che si prenderà
                 * carico di servire il client che ha richiesto la
connessione
                 */
                new Thread(new Request(client, logger)).start();
 
                /* dopo aver creato il thread, il ciclo continua in attesa
                 * di eventuali altri clients... 
                 */
            }
        } catch (IOException ex) {
            logger.error("Apertura della socket fallita");
            logger.error(ex.getMessage());
        }
    }
QUESTO PROVIENE DALLA CLASSE REQUEST
    /**
     * Costruttore predefinito
     * 
     * @param client la socket client da agganciare al thread
     * @param logger il logger già istanziato
     */
    public Request(Socket client, Logger logger) {
 
        this.client = client;
        this.logger = logger;
 
        // ottiene gli stream di input e output della socket
        try {
            in = new BufferedReader( new
InputStreamReader( client.getInputStream() ) );
            out = new BufferedWriter( new
OutputStreamWriter( client.getOutputStream() ) );
            //out = new DataOutputStream( new
BufferedOutputStream(client.getOutputStream()) );
            //in = new DataInputStream( client.getInputStream() );
        } catch (IOException ex) {
            synchronized(logger) {
                logger.error("Impossibile stabilire una connessione col
client: " + ex.getMessage());
            }
        }
    }
 
    // il corpo principale del thread
    public void run() {
        // stabilisce un protocollo di comunicazione col client
        String input;
        try {
                // QUESTO E' IL PUNTO IN CUI SI BLOCCA E NON VA PIU' AVANTI
            input = in.readLine();
                // IL CODICE SEGUENTE VIENE ESEGUITO 
                // SOLO QUANDO KILLO IL CLIENT :(
            if (input.equals("Hello Server")) {
                out.write("Hello Client");
                out.flush();
 
logger.info
("Client accettato.");
            } else {
 
logger.info
("Client non riconosciuto.");
                disconnect();
                return;
            }
        } catch (IOException ex) {
            logger.error("Errore di I/O con la sockek");
            disconnect();
            return;
        } catch (NullPointerException ex) {
            logger.error("Il client ha chiuso la connessione");
            disconnect();
            return;
        }
        /* entra in un loop che durerà fin quando
         * il client non invierà il comando "close"
         * o fin quando non si chiuderà la socket
         */
        while (true) {
            try {
                // legge il comando dalla socket
                input = in.readLine();
                // lo logga
 
logger.info
("Ricevuto comando: " + input);
 
                // se riceve il comando close esce dal ciclo
                if (input.equals("close"))
                    break;
            } catch (IOException ex) {
                // se c'è stato un errore di I/O, logga l'errore
                logger.error("Impossibile leggere dalla socket.");
                // ed esce dal ciclo
                break;
            }
        }
 
        disconnect();
    }
E QUESTO E' IL CLIENT
    private boolean connect(String host, int port) {
 
        // mostra le informazioni sullo standard output
        System.out.println("Tentativo di connessione a " + host + ":" + port
+ " in corso..." );
 
logger.info
("Tentativo di connessione a " + host + ":" + port);
 
        try {
            // crea un'istanza dell'oggetto socket
            socket = new Socket();
            // tenta la connessione col server
            socket.connect(new InetSocketAddress(host, port),
DEFAULT_TIMEOUT);
        } catch (UnknownHostException ex) {
            System.out.println("Host non trovato: " + host);
            logger.error("Host non trovato: " + host);
            socket = null;
            return false;
        } catch (IOException ex) {
            System.out.println("Impossibile stabilire una connessione col
server!");
            logger.error("Impossibile stabilire una connessione col
server.");
            socket = null;
            return false;
        }
        System.out.println("Connesso a " + host + ":" + port);
 
logger.info
("Connesso a " + host + ":" + port);
 
        try {
            out = new BufferedWriter( new
OutputStreamWriter( socket.getOutputStream() ) );
            in = new BufferedReader( new
InputStreamReader( socket.getInputStream() ) );
            //out = new DataOutputStream( new
BufferedOutputStream(socket.getOutputStream()) );
            //in = new DataInputStream(socket.getInputStream());
        } catch (IOException ex) {
            System.out.println("Errore durante l'apertura della socket!");
            logger.error("Errore durante l'apertura della socket.");
            socket = null;
            return false;
        }
        // Stabilisce un protocollo di comunicazione con il server per
identificarlo
        try {
            out.write("Hello Server");
            out.flush();
                // QUESTO E' IL PUNTO IN CUI SI BLOCCA E NON VA PIU' AVANTI
            String input = in.readLine();
            if (input.equals("Hello Client")) {
                System.out.println("Server accettato.");
 
logger.info
("Server accettato.");
            } else {
                System.out.println("Server non riconosciuto.");
                logger.error("Server non riconosciuto");
                socket = null;
                return false;
            }
        } catch (IOException ex) {
            System.out.println("Impossibile scrivere sulla socket!");
            logger.error("Impossibile scrivere sulla socket.");
            socket = null;
            return false;
        }
        // tutto OK
        return true;
    }
Ovviamente non ho riportato tutto per brevità.
Ringrazio chiunque si interessi anche minimamente al mio problema.
Ciao

Il server ti si blocca (ma farebbe la stessa fine il client poco dopo) 
_esattamente_ perchè usi BufferedReader: readLine infatti ti si blocca 
fino a che:
1. il buffer non è pieno
2. non arriva un EOF (tipo killando il client)
Altra cosa: guarda che usando il BufferedWriter come fai tu, aggiungi 
overhead e basta: a che ti serve se ci scrivi dentro poco e flushi 
subito? (naturalmente, se hai intenzione di scriverci _tanta_ roba va 
benissimo avere il buffer)

 metodo flush() dopo ogni scrittura.
Dai un occhiata alla documentazione:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/BufferedReader.html#readLine()
readLine() legge una riga, identifica la fine di una riga con dei 
caratteri ben precisi ('\n', '\r') che tu non mandi. E lui è lì che 
aspetta...
Prova a inviare "Hello Server\n\r" e vedrai che funziona.

 2. non arriva un EOF (tipo killando il client)
Assolutamente.
readLine() legge una _riga_ di testo, la riga di testo termina con 
"\r\n" o "\n" e lui banalmente aspetta solo questi caratteri.

OPS!
Mi sa proprio che ho scritto una castroneria!
Ho sempre pensato che i BufferedReader e Writer funzionassero come ho 
scritto io, e infatti non li usavo mai via rete... :)
Scusa Neo e grazie Vincent
Ah, Vincent, la mancanza dell'a-capo m'era proprio sfuggita... occhio di 
falco! :)


Giorgio Gallo wrote:

il flush in continuazione l'ho messo perché pensavo che fosse necessario
(visto che senza non funzionava...)

Vincent Vega wrote:

Ti ringrazio tantissimo, ho aggiunto la newline \n ed ora funziona
perfettamente.