Un serveur HTTP simple avec Java / Socket?

Je suis en train de créer un petit serveur HTTP qui retourne une page statique

Hello!

… J’ai essayé avec des sockets avec Java:

  public static void main(Ssortingng[] 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 rest bloqué sur l'attente d'une demande client Socket clientSocket = serverSocket.accept(); System.err.println("Nouveau client connecté"); // on ouvre un stream 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 stream d'écriture. // la donnée lue est donc retournée exactement au même client. Ssortingng 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("Exemple"); out.write("

Ceci est une page d'exemple.

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

ce code ne contient aucune erreur et j’ai reçu une réponse du navigateur comme ceci:

 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 

Mais mon problème est que je ne reçois aucune page sur le navigateur? Toute aide s’il vous plaît?

PS: J’ai déjà lu cet article: http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol , (désolé pour la langue française …)

En plus du \ r \ n après chaque ligne d’en-tête de requête, vous devez envoyer une ligne vide après l’en-tête. Exemple:

 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("Hello!"); // Content... 

J’ai corrigé votre code pour qu’il fonctionne (mais ce n’est toujours pas parfait, vous devez gérer chaque requête dans un thread séparé, par exemple avec java.util.concurrent.ThreadPoolExecutor):

 public static void main(Ssortingng[] 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 rest bloqué sur l'attente d'une demande client Socket clientSocket = serverSocket.accept(); System.err.println("Nouveau client connecté"); // on ouvre un stream 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 stream d'écriture. // la donnée lue est donc retournée exactement au même client. Ssortingng 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("Exemple"); out.write("

Ceci est une page d'exemple.

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

Ceci est une réponse à votre dernière question seulement et la raison pour laquelle rien n’est visible dans le navigateur est que vous avez calculé le nombre de caractères de manière incorrecte.

Il devrait être 57 au lieu de 59.

Mieux encore, le nombre de caractères doit être calculé automatiquement, mais je pense que votre échantillon n’est qu’un échantillon.

Quelle machine utilisez-vous? Quel OS? Si vous utilisez un ordinateur UNIX, alors println ne fonctionnera pas car il n’envoie qu’un caractère LF. HTTP nécessite CR et LF pour ses en-têtes. Essayez d’append \ r à la fin de vos chaînes et voyez si cela fonctionne.

Oh aussi, votre:

  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"+ 

Il imprime une seule longue chaîne.

Modifiez-les en une println pour chaque chaîne ou ajoutez \ r \ n à la chaîne.

Vous avez besoin des séparateurs de ligne corrects ( \r\n ) entre chaque sortie de ligne. Il ne suffit pas de les concaténer – ce que vous pouvez voir si vous imprimez la réponse.

Juste un rappel: ce n’est pas un serveur HTTP, comme le titre le suggère. C’est un socket qui écrit une réponse HTTP spécifique codée en dur (en supposant qu’il soit corrigé en fonction des suggestions des autres réponses). Même si vous avez modifié dynamicment l’en-tête de contenu et de longueur de contenu renvoyé, cela ne suffit pas pour être compatible avec le protocole HTTP.

Comme j’ai appris la rude expérience en écrivant JLHTTP , HTTP est bien plus que cela. Ce n’est pas si compliqué, mais il y a beaucoup de détails et d’exigences à traiter correctement. Vous pouvez lire les RFC (le protocole de base est défini dans la RFC 7230 ou l’ancienne RFC 2616) pour en savoir plus sur ce que cela implique.

Je peux également proposer le code source JLHTTP comme référence pour une implémentation minimale conforme d’un serveur HTTP bien documentée – il s’agit d’un fichier, contenant actuellement environ 3 000 lignes, dont presque la moitié est de la documentation. Son objective est d’être minuscule, mais conforme. Je pense que regarder le code peut être utile pour tous ceux qui veulent savoir ce qu’un serveur HTTP doit faire. Comme je l’ai dit – pas très compliqué, mais avec beaucoup de petits détails.

En réalité, pour être exact, JLHTTP n’est pas aussi minime que possible. Il inclut quelques fonctionnalités supplémentaires utiles, telles que la gestion de données de formulaire en plusieurs parties pour le téléchargement de fichiers ou la prise en charge de HTTPS, qui ne sont pas requirejses par le protocole HTTP lui-même. Mais vous pouvez facilement extraire ces parties (ou simplement les ignorer) et parvenir à une implémentation vraiment minimale du serveur HTTP Java.