Vue d'ensemble

Comme pour la plupart des applications et outils de développement, le meilleur point de départ est généralement un simple exemple Hello World !. L'application Java Hello World habituelle démarre, affiche Hello World puis se termine. Cela n'est pas très intéressant pour démontrer un outil d'exécution et de surveillance de services. Dans le cas du Java Service Wrapper, un exemple pouvant être installé puis rester en cours d'exécution en tant que service Windows ou démon UNIX est nécessaire.

Cette page décrit notre application d'exemple Serveur Hello World et vous guide dans le processus de compilation. La page Comment exécuter mon application Java en tant que service Windows ? utilisera cet exemple pour vous accompagner dans le processus de configuration et d'installation rapides de cet exemple afin de l'exécuter en tant que service Windows avec le Java Service Wrapper.

Cette application d'exemple Hello World lance un thread démon, qui écoute sur le port 9000 les clients textuels simples se connectant via telnet. Elle se contente ensuite de renvoyer en écho toute entrée jusqu'à ce qu'elle trouve l'entrée exit, auquel cas cette connexion particulière sera fermée.

Bien que cela soit un peu plus compliqué que l'exemple Hello World typique, cela vous permet d'exécuter une application serveur simple, capable d'interagir avec un programme client, suivant le modèle de conception fondamental client-serveur.

Code source de l'exemple

Pour garder notre exemple propre et le faire fonctionner correctement avec nos exemples, veuillez commencer par un répertoire vide à l'emplacement de votre choix que nous appellerons %HELLO_HOME%. Veuillez créer les répertoires lib\classes et src\java dans %HELLO_HOME%. Vous devriez obtenir ce qui suit :

Structure des répertoires
%HELLO_HOME%\
  lib\
    classes\
  src\
    java\

Créez ensuite un fichier unique dans le répertoire src\java nommé HelloWorldServer.java et ouvrez-le dans un éditeur. Copiez le code source suivant dans le fichier et enregistrez-le.

HelloWorldServer.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class HelloWorldServer
    implements Runnable
{
    private final Socket m_socket;
    private final int m_num;

    HelloWorldServer( Socket socket, int num )
    {
        m_socket = socket;
        m_num = num;
        
        Thread handler = new Thread( this, "handler-" + m_num );
        handler.start();
    }
    
    public void run()
    {
        try
        {
            try
            {
                System.out.println( m_num + " Connected." );
                BufferedReader in = new BufferedReader( new InputStreamReader( m_socket.getInputStream() ) );
                OutputStreamWriter out = new OutputStreamWriter( m_socket.getOutputStream() );
                out.write( "Welcome connection #" + m_num + "\n\r" );
                out.flush();
                
                while ( true )
                {
                    String line = in.readLine();
                    if ( line == null )
                    {
                        System.out.println( m_num + " Closed." );
                        return;
                    }
                    else
                    {
                        System.out.println( m_num + " Read: " + line );
                        if ( line.equals( "exit" ) )
                        {
                            System.out.println( m_num + " Closing Connection." );
                            return;
                        }
                        //else if ( line.equals( "crash" ) )
                        //{
                        //    System.out.println( m_num + " Simulating a crash of the Server..." );
                        //    Runtime.getRuntime().halt(0);
                        //}
                        else
                        {
                            System.out.println( m_num + " Write: echo " + line );
                            out.write( "echo " + line + "\n\r" );
                            out.flush();
                        }
                    }
                }
            }
            finally
            {
                m_socket.close();
            }
        }
        catch ( IOException e )
        {
            System.out.println( m_num + " Error: " + e.toString() );
        }
    }
    
    public static void main( String[] args )
        throws Exception
    {
        int port = 9000;
        if ( args.length > 0 )
        {
            port = Integer.parseInt( args[0] );
        }
        System.out.println( "Accepting connections on port: " + port );
        int nextNum = 1;
        ServerSocket serverSocket = new ServerSocket( port );
        while ( true )
        {
            Socket socket = serverSocket.accept();
            HelloWorldServer hw = new HelloWorldServer( socket, nextNum++ );
        }
    }
}

L'application démarre et commence à écouter sur le port 9000 les connexions distantes provenant de n'importe quelle source. À chaque nouvelle connexion acceptée, un thread gestionnaire dédié est créé pour gérer toute la communication avec cette connexion jusqu'à sa fermeture.

Le thread gestionnaire lit puis renvoie en écho toute ligne de texte au client. Si une ligne de texte contenant uniquement le mot exit est reçue, la connexion du client sera fermée.

Compilation de l'exemple

La compilation de l'exemple est une tâche simple. Commencez par ouvrir une invite de commandes ou un shell sous UNIX et placez-vous dans le répertoire %HELLO_HOME%, que nous avons créé ci-dessus, à l'aide de la commande cd.

L'exemple peut maintenant être compilé à l'aide de la commande suivante :

Compilation de l'exemple :
javac -d lib\classes src\java\HelloWorldServer.java

Si vous obtenez une erreur indiquant que la commande javac est introuvable, veuillez vous assurer qu'un SDK Java est installé sur votre système. Si tout s'est bien passé, vous devriez retrouver l'invite sans aucune sortie supplémentaire une fois la compilation terminée.

Veuillez vérifier que le fichier de classe a bien été créé en exécutant :

Vérification du fichier de classe :
dir lib\classes

Félicitations, vous avez compilé avec succès l'exemple HelloWorldServer.

Exécution de l'exemple

L'exécution de l'exemple se fait en lançant la commande suivante depuis le répertoire %HELLO_HOME%.

Exécution de l'exemple :
java -classpath lib\classes HelloWorldServer

Si tout fonctionne, vous devriez voir ce qui suit :

Exemple de sortie :
Accepting connections on port: 9000

Connexion en tant que client

Essayons maintenant de connecter un client à notre serveur et voyons ce qui se passe. Commencez par ouvrir une seconde invite de commandes et connectez-vous à l'aide de telnet :

Connexion avec Telnet :
telnet localhost 9000

Une fois connecté, vous devriez recevoir une réponse indiquant votre numéro de connexion. Ensuite, tout texte que vous saisissez suivi de la touche Entrée vous sera renvoyé en écho.

Exemple de session telnet :
Welcome connection #1
Test
echo Test
Hello there world!
echo Hello there world!

Lorsque vous avez terminé votre conversation avec le serveur, vous pouvez fermer votre connexion en saisissant exit seul sur sa propre ligne.

Notre serveur d'exemple est également capable d'accepter des connexions telnet depuis n'importe quel ordinateur pouvant voir le serveur. Si vous rencontrez toutefois des problèmes de connexion, veuillez d'abord vous assurer qu'aucun pare-feu ne fait obstacle.

Faire planter le serveur

L'exemple ci-dessus convient parfaitement comme simple serveur Java autonome. Mais nous souhaitons montrer comment le Java Service Wrapper peut contribuer à rendre notre petit serveur d'exemple beaucoup plus stable afin que votre organisation puisse commencer à s'y fier pour des systèmes critiques.

Pour commencer, nous voulons ajouter une nouvelle commande crash afin de permettre à un client connecté de crash la JVM. Bien qu'il soit possible de provoquer un véritable plantage en utilisant divers bogues connus de la JVM, beaucoup d'entre eux ne fonctionnent que sur certaines plates-formes ou avec des versions spécifiques de Java. Pour cet exemple, nous simulerons un plantage en appelant Runtime.getRuntime().halt(0) pour quitter instantanément la JVM sans effectuer un arrêt propre.

Veuillez rouvrir le fichier source HelloWorldServer.java dans un éditeur et mettre à jour le code comme suit :

HelloWorldServer.java (modification)
    ...
    System.out.println( m_num + " Read: " + line );
    if ( line.equals( "exit" ) )
    {
        System.out.println( m_num + " Closing Connection." );
        return;
    }
    else if ( line.equals( "crash" ) )
    {
        System.out.println( m_num + " Simulating a crash of the Server..." );
        Runtime.getRuntime().halt(0);
    }
    else
    {
        System.out.println( m_num + " Write: echo " + line );
        out.write( "echo " + line + "\n\r" );
        out.flush();
    }
    ...

L'exemple peut maintenant être recompilé et exécuté à l'aide des mêmes commandes que ci-dessus.

Essayez maintenant de vous connecter au serveur et d'envoyer la commande : crash. Notre petit serveur d'exemple s'arrêtera bien entendu et nous ne pourrons plus nous connecter ni utiliser le serveur depuis telnet. De toute évidence, s'il s'agissait d'un serveur critique, l'administrateur système recevrait un appel téléphonique dès qu'un utilisateur serait gêné.

Pour résoudre ce problème, veuillez consulter la page Comment exécuter mon application Java en tant que service Windows ? pour des instructions sur la façon de transformer ce simple serveur d'exemple en service Windows ou démon UNIX capable de se rétablir automatiquement après notre exemple de plantage, ainsi qu'après un certain nombre d'autres problèmes.