Question

Je commence tout juste avec Java Programmation Socket, et j'ai été la lecture de la littérature sur les sockets ici.Le code ci-dessous est un exemple d'un livre que j'ai pris qui me demande de trouver le bug.La comparaison avec la littérature même si je ne suis pas le voir tout les bugs.La création de la socket, bufferedreader, et printwriter semblent corrects, et ils sont entourés dans un bloc try-catch ainsi.Le sont correctement "close()"ed dans un bloc try-catch ainsi.Est-il une erreur lors du passage de ces process()?Toute aide serait appréciée.

import java.net.*;
import java.io.*;

class main{

public void process(PrintWriter out, BufferedReader in, Socket echoSocket){
//....
}

public void processData() {
    Socket echoSocket;
    PrintWriter out;
    BufferedReader in;
    try{
        echoSocket = new Socket("server.company.com", 8081);
        out = new PrintWriter(echoSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
    }
    catch (Exception e) {
        System.err.println("Exception has occured");
        return;
    }
    process(out, in, echoSocket);
    try {
        out.close();
        in.close();
        echoSocket.close();
    }
    catch(IOException e) {
        System.err.println("IOException has occurred.");
    }
  }
}
Était-ce utile?

La solution

Bien que, malgré les fautes de frappe, on ne peut que deviner ce que le "bug" est, ce code a un problème avec la gestion des erreurs.Plus précisément, dans la disposition de ressources.

Discussion sur les ressources

Quelles sont les ressources ?

En gros :tout Objet Java qui s'appuie sur l'OS sous-jacent au niveau des ressources.Principalement :IO ressources (d'entrée et de sortie des ruisseaux, des canaux), les Sockets.Mais le plus important :si la "chose" que vous utilisez dispose d'un close, dispsose, shutdown ou tout comme, il détient sur les ressources à l'interne.
Il y a quelques exceptions près (notamment ByteArrayInputStream détient pas de ressources, mais de mémoire), mais ce sont des détails de mise en œuvre :si vous vous en tenez à leur interface (et vous devriez, ce est un "contrat"), tous les cours d'eau doit être fermé.
Depuis Java 7, la plupart de ces objets dans l'API Java de mettre en œuvre la AutoCloseable l'interface, mais beaucoup de 3ème parties n'ont pas nécessairement portés à leur code (et peut-être que certains ne peuvent pas, pour d'autres raisons).

Comme l'un des code évaluateurs dans mon entreprise :J'ai arrêter de lire et je rejette tout code dès que je ne vois pas un appel sécurisé à l' close méthode d'une ressource.Par paiement sécurisé, je veux dire à l'intérieur d'une clause finally, qui est garanti pour être exécuté.

Règle de base sur les ressources

Tout ressources obtenues par votre programme doit être libéré dans un finally clause (certains même ajouter :de son propre).

Quel est le cycle de vie d'une ressource Bien:

  1. Vous l'obtenir
  2. Vous l'utilisez
  3. À la libération

Dans votre code, c'est à

ResourceObject myObject = null;
try {
    myObject = getResource();
    processResource(myObject);
} finally {
    if(myObject != null) {
        try {
            myObject.close();
        } catch (Exception e) {
            // Usually there is nothing one can do but log
        }
    }
}

Depuis Java 7, si l'objet de la ressource met en œuvre AutoCloseablevous avez une nouvelle façon d'écrire qui, on l'appelle le "essayez avec des ressources".

try(ResourceObject myObject = getResource()) {
    process(myObject);
}

Vous ne voyez pas la enfin, mais il est là, le compilateur écrit la clause finally pour vous dans ce cas.

Ce sur de multiples ressources ?

Bien :des ressources multiples, de multiples finallys.L'idée est de séparer les causes des défaillances dans les différents enfin clauses.Dites que vous voulez copier un fichier...

public void myCopy() throws IOException {
InputStream source = null;
    try {
    source = new FileInputStream("yourInputFile");
        // If anything bad happens, I have a finally clause that protects this now   
        OutputStream destination = null;
    try {
        destination = new FileOutputStream("yourOurputFile"); // If fails, my Input will be closed thanks to its own finally
            performCopy(source, destination); // If this fail, my destination will also be closed thanks to its own finally
        } finally {
            if(destination!=null) { try { destination.close(); } catch (Exception e) {/* log*/ }}
        }
    } finally {
        if(source!=null) { try { source.close(); } catch (Exception e) {/* log*/ }}
    }
}

Ou, avec Java 7 de la syntaxe, nous avons la plus courte (avis de non responsabilité :Je n'ai pas de Java7 droit maintenant, ne peut donc pas vraiment vérifier si cette compile) :

try(
    InputStream input = new FileInputStream("in");
    OutputStream output = new FileOutputStream("out")) {
    performCopy(input, output);
} catch(IOException e) {
    // You still have to deal with it of course.
}

C'est TELLEMENT passe-partout !

Oui, il est.C'est pourquoi nous avons bibliothèques.On pourrait dire que vous ne devriez pas écrire un tel code.Utilisation standard, bien comporté des bibliothèques comme commons IO, ou d'utiliser une de leurs méthodes de l'utilitaire.Ou plus récent JDK méthodes comme l' Files API, et voir comment cela fonctionne.

Commons IO a une pratique IOUtils.closeQuietly() suite de méthodes de fermeture de flux.

Essayez avec des ressources de Pièges

Il y a des ramifications dans le "essayez avec des ressources" appel que aller un peu plus profond que cela.Elles comprennent:Que faire si je veux faire quelque chose avec les exceptions qui se produisent dans la clause finally ?Comment puis-je différencier qu'à partir d'une exception qui aurait eu lieu au cours de performCopy?Un autre cas est :ce qui se passe ici :

try(Reader reader = new InputStreamReader(new FileInputStream("in"), "an encoding that is not supported")) {
  // Whatever
}

Il arrive qu'une UnsupportedEncodingException est levée, mais après l' FileInputStream est instanciée.Mais comme l' FileInputStream n'est pas le sujet de l'essai de la clause, il ne sera PAS fermé.Vous avez un Fichier descripteur de fuite.Essayer ça un millier de fois, et votre JVM ne sera pas en mesure d'ouvrir des fichiers, vous OS vous dira "nombre maximum de fichiers ouverts dépassé" (ulimit n'a généralement que sous UNIX)

De retour de vos prises de courant

Alors, quelles sont vos ressources ?

Eh bien, tout d'abord, on peut remarquer que la seule vraie ressource, votre Socket exemple, parce que le Socket javadoc dit (javadoc):

 * <p> Closing this socket will also close the socket's
 * {@link java.io.InputStream InputStream} and
 * {@link java.io.OutputStream OutputStream}.

Si votre Entrée et les flux de Sortie sont liés à votre Prise, et c'est assez.

Quel est le problème avec votre code

L'ajout de commentaires un original de votre code:

try{
    echoSocket = new Socket("server.company.com", 8081);
    out = new PrintWriter(echoSocket.getOutputStream(), true); // This can throw IOException
    in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // Ditto
}
catch (Exception e) {
    // If an exception was thrown getting any of the streams, we get there
    System.err.println("Exception has occured");
    // And you return without closing the socket. It's bad !
    return;
}
// Let's assume everything worked, no exception.
process(out, in, echoSocket); // This may throw an exception (timeout, socket closed by peer, ...) 
                              // that is uncaught (no catch clause). Your socket will be left unclosed as a result.
try {
    out.close();              // This can fail
    in.close();               // This too
    echoSocket.close();       // And this too - although nothing you can do about it
}
catch(IOException e) {
    // if out.close fails, we get here, and in.close and socket.close 
    // never got a chance to be called. You may be leaking resources 
    System.err.println("IOException has occurred.");
}

Une mise en œuvre sûre

Socket echoSocket = null;
try {
    // open socket, 
    echoSocket = new Socket("server.company.com", 8081); // protected by finally
    out = new PrintWriter(echoSocket.getOutputStream(), true); // protected
    in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream())); // protected
     process(out, in, echoSocket); // Still protected
} catch (Exception e) {
    // Your current error handling
} finally {
    // Anyway, this close will be called if needs be.
    if(echoSocket != null) { 
        try { echoSocket.close(); } catch (Exception e) { /* log */}
        // See javadoc, this has closed the in & out streams too.
    }
}

Autres conseils

public void process(){PrintWriter out, BufferedReader in, Socket echoSocket){

devrait être

public void process(PrintWriter out, BufferedReader in, Socket echoSocket){

sinon tout me semble bien

essayez ceci, je pense que vous avez manqué un point-virgule

public void processData() {
Socket echoSocket;
PrintWriter out;
BufferedReader in;
try{
    echoSocket = new Socket("localhost", 8080);
    out = new PrintWriter(echoSocket.getOutputStream(), true);
    in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
}
catch (IOException e) {
    System.err.println("Exception has occured");
    return;
}
process(out, in, echoSocket);
try {
    out.close();
    in.close();
    echoSocket.close();
}
catch(IOException e) {
    System.err.println("IOException has occurred.");
}


}
public void process (PrintWriter out,  BufferedReader in, Socket echoSocket)
{

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top