Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot output the stream to the browser

I just written a small program to test something, as below:

public class Main {

    public static void main(String[] args){
        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        DataInputStream dataInputStream= null;

        BufferedWriter bufferedWriter = null;
        String line ;

        try {
            serverSocket = new ServerSocket(80);
            clientSocket = serverSocket.accept();

            dataInputStream = new DataInputStream(clientSocket.getInputStream());

            while((line = dataInputStream.readLine()) != null){
                System.out.println(line);
            }

            bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            bufferedWriter.write("HTTP/1.0 200 OK \n Date: Fri, 31 Dec 1999 23:59:59 GMT \n Content-Type: text/html \n Content-Length: 1354 \n <html>abcde<html/>");

            bufferedWriter.flush();

        } catch (IOException e) {
            System.out.println("socket port cannot be opened.");
            e.printStackTrace();
        } finally{
            try {
                serverSocket.close();
                bufferedWriter.close();
            } catch (IOException e) {
                System.out.println("socket port cannot be closed.");
                e.printStackTrace();
            }
        }


    }

}

I found the http response format from the internet, it should be correct. The problem is my browser keep on waiting for the response data (determine from the spinning logo), but the data is not returned successful. What mistake I have made?

I connect to the Java program by typing "localhost" in the browser, I can print out the request string in Java program but only fail to send back the response.

like image 344
Sam YC Avatar asked Aug 03 '12 17:08

Sam YC


2 Answers

First things first, there are a few issues with the HTTP message being sent: Each line of an HTTP message is separated/ended by CR LF, rather than just a line feed (although I doubt this could be the problem, you should replace "\n" with "\r\n"). In addition, the Content-Length isn't equal to the real size of the message's body, which should be replaced. Before the actual body, all HTTP messages should have an empty line, which you have not. Finally, the forward slash at <html/> should also come before html, like this: </html>

To sum up:

bufferedWriter.write("HTTP/1.0 200 OK\r\nDate: Fri, 31 Dec 1999 23:59:59 GMT\r\nContent-Type: text/html\r\nContent-Length:18\r\n\r\n<html>abcde</html>");

Now for the real issue: the reading loop was constantly waiting for more data. Comparing the result of readLine() to null actually doesn't do what you were looking for. TCP connections make streams of data, and you never know if the client just stopped sending data in a particular moment. Instead, you can read until you find an empty line, which marks the end of the HTTP message's head. Web browsers usually do not send additional content in GET messages, therefore you will not be missing any data.

    BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    while(!(line = reader.readLine()).isEmpty()){
        System.out.println(line);
    }
like image 198
E_net4 stands with Ukraine Avatar answered Oct 18 '22 19:10

E_net4 stands with Ukraine


Could it be the Content-Length header field? Try replacing the response with this:

bufferedWriter.write("HTTP/1.0 200 OK \n Date: Fri, 31 Dec 1999 23:59:59 GMT \n Content-Type: text/html \n Content-Length: 18\n <html>abcde<html/>");

(Notice the Content-Length: 18 vs. the original Content-Length: 1354)

I suspect the browser is waiting for your application to send more data.

Edit: This works for me:

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

public class Main {

    public static void main(String[] args) throws Exception{
        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        DataInputStream dataInputStream= null;

        BufferedWriter bufferedWriter = null;

        try {
            serverSocket = new ServerSocket(8080);
            clientSocket = serverSocket.accept();

            BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            while (clientSocket.getInputStream().available() > 0) {
                String line = reader.readLine();

                if (line == null) {
                    break;
                }

                System.out.println(line);
            }

            bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            bufferedWriter.write("HTTP/1.0 200 OK \n Date: Fri, 31 Dec 1999 23:59:59 GMT \n Content-Type: text/html \n\n <html>abcde<html/>");
            bufferedWriter.flush();
            clientSocket.close();
        } catch (IOException e) {
            System.out.println("socket port cannot be opened.");
            e.printStackTrace();
        } finally{
            try {
                serverSocket.close();
                bufferedWriter.close();
            } catch (IOException e) {
                System.out.println("socket port cannot be closed.");
                e.printStackTrace();
            }
        }


    }

}

The culprit was the while loop. The method you were calling to fetch more data was blocking until that data was available (which would never happen). I'm not sure whether or not what I did was completely necessary, but it works.

like image 22
John Girata Avatar answered Oct 18 '22 18:10

John Girata