A Simple Http Server with Java/Socket

A Simple Http Server with Java/Socket?

In addition to the \r\n after every request header line, you have to send an empty line after the header. Example:

out.write("HTTP/1.0 200 OK\r\n");
// Header...
out.write("Last-modified: Fri, 09 Aug 1996 14:21:40 GMT\r\n");
out.write("\r\n"); // The content starts afters this empty line
out.write("<TITLE>Hello!</TITLE>");
// Content...

I corrected your code so that it works (but it is still not perfect, you should handle every request in a seperate thread, e.g. with java.util.concurrent.ThreadPoolExecutor):

public static void main(String[] args) throws Exception {
// création de la socket
int port = 1989;
ServerSocket serverSocket = new ServerSocket(port);
System.err.println("Serveur lancé sur le port : " + port);

// repeatedly wait for connections, and process
while (true) {
// on reste bloqué sur l'attente d'une demande client
Socket clientSocket = serverSocket.accept();
System.err.println("Nouveau client connecté");

// on ouvre un flux de converation

BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

// chaque fois qu'une donnée est lue sur le réseau on la renvoi sur
// le flux d'écriture.
// la donnée lue est donc retournée exactement au même client.
String s;
while ((s = in.readLine()) != null) {
System.out.println(s);
if (s.isEmpty()) {
break;
}
}

out.write("HTTP/1.0 200 OK\r\n");
out.write("Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n");
out.write("Server: Apache/0.8.4\r\n");
out.write("Content-Type: text/html\r\n");
out.write("Content-Length: 59\r\n");
out.write("Expires: Sat, 01 Jan 2000 00:59:59 GMT\r\n");
out.write("Last-modified: Fri, 09 Aug 1996 14:21:40 GMT\r\n");
out.write("\r\n");
out.write("<TITLE>Exemple</TITLE>");
out.write("<P>Ceci est une page d'exemple.</P>");

// on ferme les flux.
System.err.println("Connexion avec le client terminée");
out.close();
in.close();
clientSocket.close();
}
}

Implementing an HTTP Server with Socket - How to Keep It Running Forever?

You need to close the socket when you're done with it.

Create a simple HTTP server with Java?

Use Jetty. Here's the official example for embedding Jetty. (Here's an outdated tutorial.)

Jetty is pretty lightweight, but it does provide a servlet container, which may contradict your requirement against using an "application server".

You can embed the Jetty server into your application. Jetty allows EITHER embedded OR servlet container options.

Here is one more quick get started tutorial along with the source code.

Java Socket HTTP GET request

There are a couple of issues with your request:

String header = "GET / HTTP/1.1\n"
+ "Host:localhost\n\n";

The line break to be used must be Carriage-Return/Newline, i.e. you should change that to

String header = "GET / HTTP/1.1\r\n"
+ "Host:localhost\r\n\r\n";

Next problem comes when you write the data to the OutputStream:

    byte[] byteHeader = header.getBytes();
out.write(byteHeader,0,header.length());

The call of readBytes without the specification of a charset uses the system's charset which might be a different than the one that is needed here, better use getBytes("8859_1"). When writing to the stream, you use header.length() which might be different from the length of the resulting byte-array if the charset being used leads to the conversion of one character into multiple bytes (e.g. with UTF-8 as encoding). Better use byteHeader.length.

    out.write(byteHeader,0,header.length());

String res = "";
/////////////READ PROCESS/////////////
byte[] buf = new byte[in.available()];

After sending the header data you should do a flush on the OutputStream to make sure that no internal buffer in the streams being used prevents the data to actually be sent to the server.

in.available() only returns the number of bytes you can read from the InputStream without blocking. It's not the length of the data being returned from the server. As a simple solution for starters, you can add Connection: close\r\n to your header data and simply read the data you're receiving from the server until it closes the connection:

StringBuffer sb = new StringBuffer();
byte[] buf = new byte[4096];
int read;
while ((read = in.read(buf)) != -1) {
sb.append(new String(buf, 0, read, "8859_1"));
}
String res = sb.toString();

Oh and independent form the topic of doing an HTTP request by your own:

    String res = "";
for(byte b : buf)
{
res += (char) b;
}

This is a performance and memory nightmare because Java is actually caching all strings in memory in order to reuse them. So the internal cache gets filled with each result of this concatenation. A response of 100 KB size would mean that at least 5 GB of memory are allocated during that time leading to a lot of garbage collection runs in the process.

Oh, and about the response of the server: This most likely comes from the invalid line breaks being used. The server will regard the whole header including the empty line as a single line and complains about the wrong format of the GET-request due to additional data after the HTTP/1.1.



Related Topics



Leave a reply



Submit