17

I am trying to implement an HTTP Server using Sockets. If the Client (For example a browser) requests a directory the server displays a list of available files. The problem arises when the client is requesting a file. I get the following error:

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)

The stacktrace shows that the problem is coming from the writeFile() methods:

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();
}

But I can't figure out what's wrong. Can you help me?

EDIT

Thanks everyone for your answers. After I read your answers I understood that the problem was that the Socket when an error occured. Here's was my wrong 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
    }
}

And my new code was looking like this:

// 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();
        }
    }
}
Charles-Eugene Loubao
  • 1,080
  • 2
  • 12
  • 22
  • 1
    You probably need to look at what's happening on the remote host (the "clent"). SUGGESTION: Try [Wireshark](http://www.wireshark.org). – FoggyDay Sep 01 '14 at 19:14
  • Your `while(true)` loop must exit normally when an IOException occurs. The new code in the edit has a new problem where the `while` loop is going to spin forever if the socket closes abnormally. – bond Sep 02 '14 at 02:44
  • @baconoverlord what do you recommend for this? – Charles-Eugene Loubao Sep 02 '14 at 02:47
  • @Charly1811 is `handleRequest` synonymous with `writeFile` ? It is simply possible I don't fully understand the missing elements to what you are showing. – bond Sep 02 '14 at 02:49
  • writefile() is called inside handleRequest() I forgot to notify it in my answer. Sorry @baconoverlord – Charles-Eugene Loubao Sep 02 '14 at 02:58
  • @Charly1811 my next question is `run()` a thread that writes > 1 file to a given or set of sockets? or does it only function for one request? Basically why are you using the `while(true)` loop? – bond Sep 02 '14 at 03:31
  • run() is used to start the server .handleRequest() processes 1 request. When the request is processed handleRequest() finish. I use a while loop to keep the server alive so it will process any upcoming request – Charles-Eugene Loubao Sep 02 '14 at 03:37

3 Answers3

15

It is possible for the TCP socket to be "closing" and your code to not have yet been notified.

Here is a animation for the life cycle. http://tcp.cs.st-andrews.ac.uk/index.shtml?page=connection_lifecycle

Basically, the connection was closed by the client. You already have throws IOException and SocketException extends IOException. This is working just fine. You just need to properly handle IOException because it is a normal part of the api.

EDIT: The RST packet occurs when a packet is received on a socket which does not exist or was closed. There is no difference to your application. Depending on the implementation the reset state may stick and closed will never officially occur.

bond
  • 1,054
  • 8
  • 15
  • It is possible for the *port* to be `CLOSING`, but that state has nothing to do with this question. It would mean that both ends had closed simultaneously, in which case this write would throw a 'socket closed' exception. – user207421 Sep 02 '14 at 00:47
  • 1
    It says `reset by peer: socket write error`. `RST` reset packets occur when a destination has received a packet for a closed socket. One of the two ends terminated the connection in an abnormal way or it was simply happening so fast (maybe on loopback) that this occurs mid-closing. I have seen this error often enough to know that all IOExceptions on `write()` should be handled as if the connection was closed. – bond Sep 02 '14 at 01:02
  • @EJP it has everything to do with the question. Tried to explain the lifecycle further than your answer of "connection that had already been closed by the peer". The error itself says "reset by peer". You shouldn't downvote people who work with sockets every day and have seen every possible kind of mid-state condition imaginable on every major OS in production. – bond Sep 02 '14 at 01:06
  • You're right @baconoverlord . When the IOException occurs, the catch() method was not called. Normaly should not close the socket and stop the program. I updated the question with the fix – Charles-Eugene Loubao Sep 02 '14 at 02:39
  • @bond A socket is only closed by the owning process. The [CLOSING](https://tools.ietf.org/html/rfc793) state of a *port* is only reached *after* a CLOSE action by the application. You don't have any information about who downvoted your answer. – user207421 Jun 20 '16 at 17:57
  • 3
    @bond The link is not working. Can you fix it? Thanks – mljrg Feb 19 '20 at 12:55
1

This problem is usually caused by writing to a connection that had already been closed by the peer. In this case it could indicate that the user cancelled the download for example.

user207421
  • 305,947
  • 44
  • 307
  • 483
-1

I face this problem but resolution is very simple. I am writing the 1 MB file in 1024 Byte Buffer causing this issue. To Understand refer code before and After Fix.

Code with Excepion

DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        FileInputStream fis = new FileInputStream(file);
        byte[] buffer = new byte[1024];
        
        while (fis.read(buffer) > 0) {
            dos.write(buffer);
        }
    

After Fixes:

DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        FileInputStream fis = new FileInputStream(file);
        byte[] buffer = new byte[102400];
        
        while (fis.read(buffer) > 0) {
            dos.write(buffer);
        }

    
Rajeev Rathor
  • 1,830
  • 25
  • 20