0

I'm working on a multi-threaded web-server for a school project. I should be able to go into the localhost on my browser and request 3 different files (.htm, .jpeg,.pdf). However, when I do this for a .htm file with the picture also inside of it (2 requests) the .htm file appears in browser but I get many broken pipe socket exceptions for each write I try to do on the picture (Assignment requires to write 1024 bytes at a time). Something is clearly wrong with the way I have implemented this but I am at a loss as to where the connection is being closed when I try to write for the second file?

I tried a few different things to try and fix this including a loop when trying to read the socket input stream but I think that defeats the purpose of the multi-threaded server.

The server:

    while(true){
        try {
            sock = servSock.accept(); // Handles the connection
            // Connection received log
            System.out.println("Connection received: " + new Date().toString() + " at " + sock.getInetAddress() + sock.getPort());
            HTTP pro = new HTTP(sock); // Client handler
            pro.run();

            ServerThread serverThread = new ServerThread(pro); 
            // Starts ServerThread
            serverThread.start();
        } catch (Exception e){
            System.out.println(e);
        }
    }

HTTP:


    public void run(){
        // Try to open reader
        try{
            readSock = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        } catch (Exception e){
            System.out.println(e);
        }

        // Open output stream
        try{
            this.out = new DataOutputStream(sock.getOutputStream()); 
            this.printOut = new PrintWriter(sock.getOutputStream()); 
        } catch (Exception e){
            System.out.println(e);
        }

        // Try to read incoming line
        try {
            this.reqMes = readSock.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        StringTokenizer st = new StringTokenizer(reqMes);

        // Parse the request message
        int count = 0;
        while(st.hasMoreTokens()){
            String str = st.nextToken();
            if (count == 1){
                this.fileName = "." + str;
            }
            count += 1;
        }
        System.out.println("File name received.");

        File file = null;
        try {
            file = new File(this.fileName);
            this.f = new FileInputStream(file); // File input stream
            this.fileExists = true;
            System.out.println("File " + this.fileName +  " exists.");
        } catch (FileNotFoundException e) {
            System.out.println(e);
            this.fileExists = false;
            System.out.println("File does not exist.");
        }

        byte[] buffer = new byte[1024];
        // Write status line
        if (this.fileExists) {
            System.out.println("Trying to write data");
            try{
                this.out.writeBytes("HTTP/1.0 " + "200 OK " + this.CRLF);
                this.out.flush();
                this.printOut.println("HTTP/1.0 " + "200 OK " + this.CRLF);
                // Write Header
                this.out.writeBytes("Content-type: " + getMime(this.fileName) + this.CRLF);
                this.printOut.println("Content-type: " + getMime(this.fileName) + this.CRLF);
                this.out.flush();

                // Read file data
                byte[] fileData = new byte[1024];

                while (this.f.read(fileData) != -1) {
                    // Write File data
                    try{
                        this.out.write(fileData,0,1024);
                        this.out.flush(); // Flush output stream
                    } catch (IOException e) {
                        System.out.println(e);
                    }
                }
                System.out.println("Flushed");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

For one .htm file in the browser, the file and html seem to appear fine. But it looks like it makes a second request for a .jpeg file within the html file and the browser gets stuck loading with java.net.SocketException: Broken pipe (Write failed) when writing the data each time at

this.out.write(fileData,0,1024);

Thank you, any help is appreciated.

  • Copy loop is incorrect. It should be `int count; while ((count = f.read(fileData)) > 0) { out,write(fileData,0,count); }`. – user207421 Oct 29 '19 at 20:58
  • @user207421 thanks for this I think it fixed some other bug I was having but I am still getting the broken pipe exception when trying to write – zaidsbaghal Oct 30 '19 at 16:16

1 Answers1

0

After much searching among different problems, I found the answer here.

The problem was with the response headers not being formatted properly which led to the connection ending prematurely. Another empty line ("\r\n") must be sent after the header.

The following code now works (this.CRLF is equal to "\r\n"):

    public void run(){
        // Try to open reader
        try{
            readSock = new BufferedReader(new InputStreamReader(sock.getInputStream()));
        } catch (Exception e){
            System.out.println(e);
        }

        // Open output stream
        try{
            this.out = new DataOutputStream(sock.getOutputStream()); // Data output
            this.printOut = new PrintWriter(sock.getOutputStream()); // Print output
        } catch (Exception e){
            System.out.println(e);
        }

        // Try to read incoming line
        try {
            this.reqMes = readSock.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        StringTokenizer st = new StringTokenizer(reqMes);

        // Parse the request message
        int count = 0;
        while(st.hasMoreTokens()){
            String str = st.nextToken();
            if (count == 1){
                this.fileName = "." + str;
            }
            count += 1;
        }
        System.out.println("File name received.");

        // Initialize file to be sent
        File file = null;
        // Try to find file and create input stream
        try {
            file = new File(this.fileName);
            this.f = new FileInputStream(file); // File input stream
            this.fileExists = true;
            System.out.println("File " + this.fileName +  " exists.");
        } catch (FileNotFoundException e) {
            System.out.println(e);
            this.fileExists = false;
            System.out.println("File does not exist.");
        }

        byte[] buffer = new byte[1024];
        // Write status line
        if (this.fileExists) {
            System.out.println("Trying to write data");
            try{
                this.out.writeBytes("HTTP/1.0 " + "200 OK " + this.CRLF);
                this.out.flush();
                // Write Header
                this.out.writeBytes("Content-type: " + getMime(this.fileName) + this.CRLF);
                this.out.flush();
                this.out.writeBytes(this.CRLF);
                this.out.flush();

                // Read file data
                byte[] fileData = new byte[1024];

                int i;
                while ((i = this.f.read(fileData)) > 0) {
                    // Write File data
                    try{
                        this.out.write(fileData,0, i);
                    } catch (IOException e) {
                        System.out.println(e);
                    }
                }
                this.out.flush(); // Flush output stream
                System.out.println("Flushed");
                closeSock(); // Closes socket
            } catch (IOException e) {
                e.printStackTrace();
            }