it-swarm.com.de

Ein einfacher HTTP-Server mit Java/Socket?

Ich erstelle gerade einen kleinen HTTP-Server, der eine statische Seite <p>Hello!</p>....__ zurückgibt. Ich habe es mit Sockets mit Java versucht:

  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())
                          ); 
            PrintWriter out = new PrintWriter(
                         new BufferedWriter(
                            new OutputStreamWriter(clientSocket.getOutputStream())), 
                         true);   

            // 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);


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

dieser Code enthält keine Fehler und ich habe eine Antwort vom Browser erhalten:

GET / HTTP/1.1
Host: localhost:1989
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.46 Safari/536.5 Comodo_Dragon/19.0.3.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Aber mein Problem ist, dass ich keine Seite im Browser bekomme? Irgendwelche Hilfe bitte?

PS: Ich habe diesen Artikel bereits gelesen: http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol , (tut mir leid für die französische Sprache ...)

23
Marwen Trabelsi

Zusätzlich zu\r\n nach jeder Anforderungskopfzeile müssen Sie eine leere Zeile nach der Kopfzeile senden. Beispiel:

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...

Ich habe Ihren Code so korrigiert, dass er funktioniert (aber er ist immer noch nicht perfekt. Sie sollten jede Anforderung in einem separaten Thread behandeln, z. B. mit 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();
    }
}
29
Joel Richard

Dies ist nur eine Antwort auf Ihre letzte Frage. Der Grund dafür, dass im Browser nichts sichtbar ist, ist, dass Sie die Anzahl der Zeichen falsch berechnet haben.

Es sollte 57 statt 59 sein.

Noch besser ist es, die Anzahl der Zeichen automatisch berechnen zu lassen, aber ich glaube, dass Ihre Probe nur eine Probe ist.

4
javabeangrinder

Welche Maschine benutzt du? Welches Betriebssystem? Wenn Sie eine UNIX-Maschine ausführen, funktioniert println nicht, da nur ein Zeichen LF gesendet wird. HTTP erfordert CR und LF für die Header. Fügen Sie\r am Ende Ihrer Zeichenfolgen hinzu und prüfen Sie, ob dies funktioniert.

Oh auch dein:

  out.println("HTTP/1.0 200 OK"+
"Date: Fri, 31 Dec 1999 23:59:59 GMT"+
"Server: Apache/0.8.4"+
"Content-Type: text/html"+
"Content-Length: 59"+
"Expires: Sat, 01 Jan 2000 00:59:59 GMT"+
"Last-modified: Fri, 09 Aug 1996 14:21:40 GMT"+

Es wird eine einzige lange Zeichenfolge gedruckt.

Ändern Sie diese in eine println für jede Zeichenfolge oder fügen Sie der Zeichenfolge\r\n hinzu.

1
Will Hartung

Sie benötigen die richtigen Zeilentrennzeichen (\r\n) zwischen jeder Zeilenausgabe. Es reicht nicht aus, sie nur zu verketten - was Sie sehen, wenn Sie die Antwort ausdrucken.

Nur eine Erinnerung: Dies ist nicht ein HTTP-Server, wie der Titel vermuten lässt. Hierbei handelt es sich um einen Socket, der eine spezifische hartcodierte HTTP-Antwort ausschreibt (vorausgesetzt, sie wird gemäß den Vorschlägen in den anderen Antworten behoben). Selbst wenn Sie den zurückgegebenen Inhalt und den Inhaltslängenheader dynamisch geändert haben, reicht dies noch nicht aus, um mit dem HTTP-Protokoll kompatibel zu sein.

Als ich auf die harte Art und Weise beim Schreiben von JLHTTP lernte, ist HTTP viel mehr als das. Es ist nicht so, dass es sehr kompliziert ist, aber es gibt viele zusätzliche Details und Anforderungen, um richtig gehandhabt zu werden. Sie können die RFCs lesen (das Kernprotokoll ist in RFC 7230 oder der ältere RFC 2616 definiert), um mehr darüber zu erfahren, was dies bedeutet.

Ich kann den JLHTTP-Quellcode auch als Referenz für eine gut dokumentierte, minimal kompatible Implementierung eines HTTP-Servers anbieten - es handelt sich um eine Datei, derzeit ~ 3K-Zeilen, von denen fast die Hälfte Dokumentationen sind. Ihr Ziel ist es, klein zu sein, aber konform. Ich denke, der Code kann für alle nützlich sein, die wissen wollen, was ein HTTP-Server zu tun hat. Wie gesagt - nicht sehr kompliziert, aber mit vielen kleinen Details.

Um genau zu sein, JLHTTP ist eigentlich nicht so minimal wie möglich - es enthält einige nützliche Zusatzfunktionen, wie z. B. die Verarbeitung von mehrteiligen Formulardaten für Dateiuploads oder die Unterstützung von HTTPS, die nicht vom HTTP-Protokoll selbst benötigt werden. Sie können diese Teile jedoch problemlos ausreißen (oder einfach überspringen) und zu einer wirklich minimalen Java-HTTP-Server-Implementierung kommen.

0
amichair