6

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.

Bhavik Ambani
  • 6,557
  • 14
  • 55
  • 86
Sam YC
  • 10,725
  • 19
  • 102
  • 158
  • I believe it's a app-server configuration. Please, see [my post](http://stackoverflow.com/questions/43453508/end-to-end-reactive-streaming-restful-service). – Igor Veloso Apr 18 '17 at 15:22

3 Answers3

3

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.

John Girata
  • 2,021
  • 15
  • 15
  • 1
    Those tricks might have worked in this case, but I wouldn't call it a valid solution. Since TCP works with streams of data, you can only know the end of particular messages from the actual protocol over it. In this case, you would have to interpret the HTTP message as it is being read, in order to find where it ends. – E_net4 Aug 03 '12 at 17:47
3

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);
    }
E_net4
  • 27,810
  • 13
  • 101
  • 139
  • sorry my bad for the – Sam YC Aug 03 '12 at 17:30
  • 1
    I updated my answer, and made it work. So did @John Girata apparently. – E_net4 Aug 03 '12 at 17:43
  • thank, your version works better because in this case, I can retrieve all the request data. I cannot understand if empty line mark the end of http message head, will the http request body be missed? – Sam YC Aug 03 '12 at 18:27
  • 1
    That's a good question: It will, but the GET message the web browser sends to your server app does not have one. The head of the message is all that the browser needs to show the requested resource. In other situations, you'd have to read the content through other means, as in, reading the content headers. See the RFC 2616 for more information on HTTP 1.1: http://www.w3.org/Protocols/rfc2616/rfc2616.html – E_net4 Aug 03 '12 at 18:32
  • I am curious about other issue, for BufferedReader.readLine() kind of method, how does it know the streaming already reach the end? For example, there is a Java TCP socket client-server program, client send some string to the server, the server is using BufferedReader.readLine() to read the data, how does it know the input already reach end since this is not HTTP anymore? Will it come out with the similar problem like this? – Sam YC Aug 03 '12 at 19:23
  • 1
    You may only find the end of the receiving stream once the connection is closed from the other side. From that moment the system is sure that no more data will be received. Once all data is read after so, the raw stream methods read() should return -1. Consequently, readLine() will return null: http://docs.oracle.com/javase/1.5.0/docs/api/java/io/BufferedReader.html#readLine%28%29 – E_net4 Aug 03 '12 at 19:43
1

I see two problems:

The content-length header says 1354 bytes will follow. You only are writing 20 or so. Content-length is optional; don't include it if you're not using the correct value.

You need a blank line at the end of the headers and before the content: ".... Content-Length: xx\n\n<html>..."

Mike Harris
  • 1,487
  • 13
  • 20