Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Serveur web full as3 avec ServerSocket

Compatible AIR 2. Cliquer pour en savoir plus sur les compatibilités.Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par goabonga (goabonga), le 19 mai 2010

Au travers ce tutoriel nous allons apprendre à utiliser la classe ServerSocket (implémentée depuis la version 2 du bundle Air).

Cette classe nous offre la possibilité de placer un écouteur sur un port ciblé, c'est idéal pour mettre en place un petit serveur web http.

La classe étend la classe EventDispatcher. A chaque ouverture d'une connexion sur le port, un événement contenant le socket est diffusé.

Un Socket est un modèle de communication IPC (Inter Process Communication) permettant de communiquer, aussi bien sur une même machine, qu'à travers un réseau TCP/IP. Il existe deux méthodes de communication :

Le mode dit connecté, utilise le protocole TCP et il est orienté connexion.
Le client, en règle générale, envoie une requête et reçoit une réponse, puis la connexion est fermée par l'émetteur.

Le mode non connecté, quant à lui, utilise le protocole UDP. Il n'est pas orienté connexion.
Le serveur émet des données vers ses clients sous forme de data-grammes. En règle générale, lors de la communication le socket client attend constamment la lecture et l'écriture de données.

Le socket se place dans une couche intermédiaire du modèle OSI. On le place entre la couche réseau et la couche de transport.

Un serveur HTTP utilise le mode dit connecté : une fois la connexion établie, les informations transitent à travers les différentes couches du modèle OSI. Lorsqu'elles transitent au sein de la couche applicative celle-ci défini le protocole de communication à utiliser. Dans notre cas c'est le protocole HTTP1, ce protocole de communication client serveur développé pour le web, permet le support d'en-têtes MIME pour décrire les données transmises.

Le serveur utilise par défaut le port 80, les clients se connectent à ce denier et lancent une commande ainsi composée :

   Ligne de commande (Commande, URL, Version de protocole)
   En-tête de requête
   [Ligne vide]
   Corps de requête

Puis le serveur retourne une réponse :

 
   Ligne de statut (Version, Code-réponse, Texte-réponse)
   En-tête de réponse
   [Ligne vide]
   Corps de réponse

Mise en place du serveur :

Il nous suffit, en soi, d'instancier la classe ServerSocket. Cette dernière possède une méthode bind permettant de lui spécifier un port et une adresse IP à écouter ainsi qu'une méthode listen qui initialise l'écoute.

De plus la classe diffuse un événement de type ServerSocketConnectEvent. Ce dernier nous informe de l'ouverture d'une connexion et donc de la création d'un socket entre un client et le serveur.

package {
	import flash.display.MovieClip;
	import flash.events.ProgressEvent;
	import flash.events.ServerSocketConnectEvent;
	import flash.net.ServerSocket;
	import flash.net.Socket;
 
	/**
	 * @author Goabonga
	 */
	public class WebServer extends MovieClip {
 
		private var _server : ServerSocket = new ServerSocket();
		private var _address : String = "0.0.0.0";
		private var _port : int = 80;
 
		/**
		 *
		 */
		public function WebServer() {
			trace(this);
			_server.addEventListener(ServerSocketConnectEvent.CONNECT, onConnectHandler);
			_server.bind(_port, _address);
			_server.listen();
		}
 
		private function onConnectHandler(event : ServerSocketConnectEvent) : void {
			trace(this + ' onConnectHandler: ' + event);
			var client : Socket = event.socket;
		}
	}
}

Si vous compilez ce code, vous constaterez qu'il vous est possible de vous connecter avec votre client HTTP à l'adresse http://127.0.0.1:80 , mais malheureusement pour l'instant notre serveur ne retourne aucune réponse et votre client HTTP restera dans l'attente de celle-ci.

Comme nous l'avons vu dans l'introduction du tutoriel, le client HTTP lance une requête contenant des informations respectant le standard HTTP. Nous allons récupérer ces informations. Pour cela il nous suffit de lire les données émises par notre client.

Modifier la méthode onConnectHandler:

		private function onConnectHandler(event : ServerSocketConnectEvent) : void {
			trace(this + ' onConnectHandler: ' + event);
			var client : Socket = event.socket;
			client.addEventListener(ProgressEvent.SOCKET_DATA, onRequestHandler);
		}

Et ajouter la méthode onRequestHandler :

		private function onRequestHandler(event : ProgressEvent) : void {
			trace(this + ' onRequestHandler: ' + event);
			var client : Socket = event.target as Socket;
			var request : String = (event.target as Socket).readUTFBytes((event.target as Socket).bytesAvailable);
			trace('request : \n' + request.split('\r').join('\n'));
		}

Maintenant, si vous ouvrez la page http:127.0.0.1:80, votre console devrait vous tracer les informations émises par le client.

  data :
  GET / HTTP/1.1
  Host: 127.0.0.1:81
  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2) Gecko/20100115 Firefox/3.6
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
  Accept-Encoding: gzip,deflate
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  Keep-Alive: 115
  Connection: keep-alive
  Cache-Control: max-age=0

Ces informations pourront être traitées pour nous fournir des détails sur notre client.

A présent nous allons retourner une réponse au format HTTP1.1 au client :

Modifier la méthode onRequestHandler :

		private function onRequestHandler(event : ProgressEvent) : void {
			trace(this + ' onRequestHandler: ' + event);
			var client : Socket = event.target as Socket;
			var request : String = (event.target as Socket).readUTFBytes((event.target as Socket).bytesAvailable);
			trace('request : \n' + request.split('\r').join('\n'));
 
			var response : String = 'HTTP/1.1 200 OK\n';
			response += 'Content-Type: text/html\n';
			response += '\n';
			response += '<?xml version="1.0" encoding="UTF-8"?>\n';
			response += '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//FR" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n';
			response += '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">\n';
			response += '<head>\n';
			response += '<title>WebServeur</title>\n';
			response += '<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />\n';
			response += '</head>\n';
			response += '<body>\n';
			response += '
<h1>WebServer HTTP 200</h1>
 
\n';
			response += '</body>\n';
			response += '</html>\n';
 
			trace('response : \n' + response.split('\r').join('\n'));
 
			client.writeUTFBytes(response);
			client.flush();
			client.close();
		}

Compilez le code et actualisez votre client HTTP.

Maintenant votre navigateur devrait recevoir la réponse et vous afficher son contenu.

Conclusion

Voilà, nous savons maintenant qu'il nous est possible de mettre en place très simplement une application Air qui fasse office de serveur web.