web-dev-qa-db-fra.com

java.net.SocketException: réinitialisation de la connexion par l'homologue: erreur d'écriture de socket lors du service d'un fichier

J'essaie d'implémenter un serveur HTTP à l'aide de sockets. Si le client (par exemple un navigateur) demande un répertoire, le serveur affiche une liste des fichiers disponibles. Le problème survient lorsque le client demande un fichier. J'obtiens l'erreur suivante:

Java.net.SocketException: Connection reset by peer: socket write error
at Java.net.SocketOutputStream.socketWrite0(Native Method)
at Java.net.SocketOutputStream.socketWrite(SocketOutputStream.Java:113)
at Java.net.SocketOutputStream.write(SocketOutputStream.Java:159)
at cf.charly1811.Java.web.RequestHandler.writeFile(RequestHandler.Java:152)
at cf.charly1811.Java.web.RequestHandler.processRequest(RequestHandler.Java:139)
at cf.charly1811.Java.web.RequestHandler.handleRequest(RequestHandler.Java:110)
at cf.charly1811.Java.web.RequestHandler.run(RequestHandler.Java:86)
at Java.lang.Thread.run(Thread.Java:745)

Le stacktrace montre que le problème vient des méthodes writeFile():

private void writeFile(File request) throws IOException 
{
    InputStream byteReader = new BufferedInputStream(new FileInputStream(request));
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = byteReader.read(buffer)) != -1) 
    {
        outputStream.write(buffer, 0, bytesRead);
    }
    byteReader.close();
}

Mais je ne peux pas comprendre ce qui ne va pas. Pouvez-vous m'aider?

[~ # ~] modifier [~ # ~]

Merci à tous pour vos réponses. Après avoir lu vos réponses, j'ai compris que le problème était que le socket lorsqu'une erreur s'est produite. Voici mon mauvais code:

// Method to process a single request
handleRequest() throw IOException
{
    // process here
    // if the client request a file
    writeFile();
    // close socket when the request is processed
}

// The method is called
public run()
{
    try{
        // If an error occurs the try/catch won't be called because it is implemented outside the loop. So when an IOException occurs, the loop just stop and exit the program
        while(true)
        {
            handleRequest();
        }
    }
    catch(IOException e) {
        // Handle exception here
    }
}

Et mon nouveau code ressemblait à ceci:

// Method to process a single request
handleRequest()
{
   try {
        // process here
        // if the client request a file
        writeFile();
        // close socket when the request is processed
    }
    // If this exception occurs the catch() method will be called
    catch(IOException e)
    {
        // handle exception here
    }
}

// The method is called
public run()
{
    while(true)
        {
            handleRequest();
        }
    }
}
12

Il est possible que la socket TCP se "ferme" et que votre code n'ait pas encore été notifié.

Voici une animation pour le cycle de vie. http://tcp.cs.st-andrews.ac.uk/index.shtml?page=connection_lifecycle

Fondamentalement, la connexion a été fermée par le client. Tu as déjà throws IOException et SocketException étend IOException. Cela fonctionne très bien. Vous avez juste besoin de gérer correctement IOException car c'est une partie normale de l'API.

EDIT: le paquet RST se produit lorsqu'un paquet est reçu sur un socket qui n'existe pas ou a été fermé. Il n'y a aucune différence dans votre application. Selon l'implémentation, l'état reset peut rester et closed ne se produira jamais officiellement.

13
bond

Ce problème est généralement dû à l'écriture sur une connexion qui a déjà été fermée par l'homologue. Dans ce cas, cela pourrait indiquer que l'utilisateur a annulé le téléchargement par exemple.

1
user207421