IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

[Sockets] Serveur Java performant


Sujet :

Entrée/Sortie Java

  1. #1
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut [Sockets] Serveur Java performant
    Bonjour à tous,
    Je me présente, je m'appelle Mickaël, j'ai 17 ans et je vais sur la Terminale. Je suis principalement développeur as 3.
    Depuis environs 6 mois je réalise un chat en 2D isométrique en Actionscripte 3.0. La partie serveur est en java. J'utilise blablaserveur que j'ai modifié pour traiter les sockets qu'il reçevait.
    Le projet a pour but de m'améliorer.
    Seulement voilà avec blablaserveur un thread est dédié par client hors j'ai cru comprendre que ce n'était pas géniale avec beaucoup de connectés.
    Le soucie c'est que je ne vois pas comment gérer les clients individuellement sans leur attribuer un thread.
    Par exemple comment envoyer un message à un unique client s'ils sont tous dans le même thread ?
    Enfin voilà c'est un peu flou c'est pour cela que je vous demande un peu d'aide pour m'éclairer sur la façon de créer un serveur performant en java.
    Si vous avez des conseils, liens, où autre je suis preneur.

    Le projet ne sera pas publique, c'est juste pour réaliser quelque chose de bien, avoir de bonnes bases pour la suite et surement le mettre open-source.

    Merci de votre aide,
    Mickaël

  2. #2
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    C'est jouable en utilisant le système de socket non bloquantes fourni dans l'API nio.

    Par contre tu vas devoir revoir ton serveur au niveau conceptuel.
    Et pour une couche réseau bien foutue tu as Netty qui propose une API très bien pensée par dessus NIO.

  3. #3
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci de ta réponse,
    Netty semble bien, malheureusement je ne trouve pas beaucoup d'explications. (je n'aime pas me contenter de copier/coller) Je continue de faire des recherches de mon côté. SI vous avez d'autres conseils concernant le langage ou l'architecture je suis preneur.

    Merci encore,
    Mickaël

  4. #4
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Le user guide n'a pas l'air si mal foutu que ça....
    http://docs.jboss.org/netty/3.2/guide/html/index.html

  5. #5
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci, en effet c'est sur quoi j'étais tombé.
    Il est très bien fait mais je ne comprends toujours pas tout. Je n'arrive pas vraiment à savoir quelle partie correspond à ce que je cherche. Si j'ai compris la connexion d'un client sur le serveur est représentée par un channel mais cela reste encore flou. Je ne comprends pas vraiment que sont les discard serveur, echo serveur et time serveur.

    Je suis désolé, il s'agit surement de questions ridicules mais je préfère tout de même vous les poser.
    La programmation serveur est vraiment une chose que j'aimerais comprendre et savoir réaliser.

    Merci de vos réponses,
    Mickaël

  6. #6
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Dans ce cas là il va falloir commencer par lire un peu de doc sur l'API nio de java, et les concepts sous jacents:

    http://gfx.developpez.com/tutoriel/java/nio/
    http://rox-xmlrpc.sourceforge.net/niotut/index.html
    http://www.google.fr/url?sa=t&source...zfAENA&cad=rja

    Ensuite pour ce qui est des discard, echo et time server, ce sont des exemple d'implémentation de RFC, il suffit de cliquer sur les liens dans le user guide pour voir à quoi correspondent ces RFC (basiquement DISCARD ne renvoie absolument rien, ECHO renvoie le contenu reçu et TIME renvoie l'heure)

  7. #7
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci beaucoup pour toutes ces réponses.
    C'est vraiment gentils d'avoir passez autant de temps pour moi, je t'en suis très reconnaissant. Je vais me pencher sérieusement sur ce que tu m'as donné. Avant de mettre le sujet comme résolu et ainsi laisser la place aux autres, j'ai une dernière question concernant les threads.
    A quoi correspondent-ils réellement ? Je les ai utilisés uniquement comme "tuyau" de communication entre un client et le serveur. Un thread si j'ai compris peut gérer plusieurs clients cela signifie qu'il peut créer plusieurs connexion avec différents clients ? Qu'elle architecture elle l'a plus conseillée ? (Un thread réception, un thread envoie, un thread connexion ?)

    Merci de m'éclairer une dernière fois.
    Avec tous mes remerciement,

    Mickaël.

  8. #8
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Les Threads en java (d'ailleurs dans tous les langages plus globalement) sont le mécanisme permettant d'exécuter des instructions en parallèle et non en série.

    Donc le Thread va exécuter le code qui lui est fourni sans devoir attendre que l'appelant aie quelque chose à réaliser, et l'appelant v&a continuer son chemin au lieu d'attendre que le code contenu dans le Thread se termine.

    Grosso modo au niveau archi pour un serveur tu as deux choix:


    • En utilisant l'ancienne API IO de java tu as un Thread maitre qui gère l'établissement d'une connexion (handshake & cie), puis crée un socket/un channel (sans lire dessus) et passe ce socket à un Thread esclave qui va réaliser le boulot de lecture des données, de traitement et d'envoi de la response. Comme la lecture sur le socket est bloquante (le read sur le socket ne rend pas la main tant qu'il n'a rien reçu), chaque connexion nécessite son propre Thread, donc on se retrouve avec un Thread esclave par requêyte en cours de traitement
    • En utilisant la nouvelle API IO de java, les socket et channels non bloquants on été introduits. De fait le read sur un channel retourne directement la main si rien n'est lu. De fait il suffira d'avoir un Thread Maitre qui gère l'établissement des connexions et qui fournira le channel à un unique Thread esclave qui gère toutes les lectures sur les socket de son coté. Dans le cas présent il y aura un seul Thread esclave pour n connexions/channels.


    Mais bon, si tu utilises Netty, la question des Threads ne se pose plus vraiment, tout est déjà géré dans l'API...

  9. #9
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    A noter que chaque méthode peut être plus performante que l'autre suivant les conditions


    • La méthode avec un Thread par connexion (old IO) est plus performante avec un nombre de clients simultanés pas énorme (mais qui peuvent envoyer beaucoup de requêtes)
    • La méthode avec un Thread global est plus performante avec un nombre élevé de clients plus élevé.

    L'avantage de Netty c'est que tu peux aussi bien faire des IO bloquantes que non bloquantes avec, en choisissant la SocketChannelFactory appropriée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
    org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;

    Ca te permettra de comparer les perfs de ton serveur suivant le type d'IO utilisé.

  10. #10
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci beaucoup, vraiment je ne sais comment te remercier, tout devient plus clair maintenant. Je revois bien les bases avant de m'attaquer à Netty.
    Un ami m'a conseillé Python, y a t-il une différence de performances où c'est surtout la façon de coder le serveur qui importe ?

    Merci beaucoup,
    sincèrement,

    Mickaël

  11. #11
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Dans l'ensemble, python, étant un langage interprété possède un déficit au niveau exécution (pas de JIT & cie).

    Ensuite dans le cadre d'un serveur, au final, le temps est surtout perdu au niveau des IO, donc au final, a moins d'avoir besoin d'un truc über performant, cas dans lequel on passera vers du code natif en C/C++ voir assembleur, la différence ne sautera pas au yeux.

    Dans l'ensemble un serveur maison codé en java sera tout de même un poil plus performant que son équivalent python...

  12. #12
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Salut,
    Encore une fois merci beaucoup, tes explications sont toujours aussi clairs et intéressantes. Je me suis donc lancé avec Netty qui est vraiment très bien. J'ai bien compris comment créer un echo serveur qui renvoie juste les données au client, mais deux petite choses me chagrinent, dans le serveurHandler j'ai une fonction qui reçoit les messages :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
        {
            Channel ch = e.getChannel();
            ch.write(e.getMessage());
            System.out.print("\nMessage - "+e.getChannel().getId().toString()+ " - "+e.getMessage().toString());
        }
    La premiere chose qui m'ennuie c'est que je n'arrive pas à récupérer le message reçut en String en faisant ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    e.getMessage().toString()
    La console renvoie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BigEndianHeapChannelBuffer(ridx=0, widx=40, cap=40)
    Le second souci vient du fait que je renvoie bien le message mais que je n'arrive pas à le traiter. Le message est au format XML. J'avais pensé récupérer la chaîne pour la transformer en XML mais je n'arrive pas à la récupérer. J'ai donc aucune idée de comment traiter les messages reçut.
    Pour finir, concernant l'envoie du message à tout les clients, j'ai pensé créer une ArrayList contenant chaque channel et parcourir l'arrayList pour envoyer le message reçut? Est-ce une bonne idée ?

    Ce sont surement des question bêtes mais ça me pose réellement un soucie. Je te remercie pour l'intention que tu me porte, je t'en suis réellement reconnaissant,

    Mickaël

  13. #13
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Il suffit de regarder l'exemple au dessus de l'echo server pour comprendre la façon d'obtenir le contenu d'un MessageEvent.

    http://docs.jboss.org/netty/3.2/guid...ex.html#d0e290

    Cf la javadoc de la classe ChannelBuffer

  14. #14
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci beaucoup,
    J'ai réussi à récupérer la chaîne de cette manière là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) 
        {
            String msg = "";
            ChannelBuffer buf = (ChannelBuffer) e.getMessage();
             while(buf.readable()) 
             {
                 msg = new StringBuffer(msg).insert(msg.length(), (char) buf.readByte()).toString();
     
             }
            System.out.print("\nMessage - "+e.getChannel().getId().toString()+ " - "+msg);
    Ca fonctionne très bien, j'ai une dernière petite question, ou plutôt une demande de confirmation. Un objet ServeurHandler est-il attribué par client ? Si oui, je peux donc créer des attributs spécifique au client comme l'id, le pseudo, l'adresse ip dans la classe ServeurHandler ?
    Mais cela ne revient-il pas à créer un thread par client ?

    Merci encore une fois, tes réponses son vraiment très clairs, tu n'étais pas obligé de prendre autant de temps pour moi, merci.

    Mickaël

  15. #15
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Non, les ServerHandler ne sont pas attribués par client. Quel que soit le Client les ServerHandler cette socket restent les même pour un ServerBootstrap.

    De fait la façon de procéder est d'avoir N handler dans le pipeline, chacun effectuant son rôle avant de passer là main au suivant (méthodes sendDownstream, sendUpstream).

    Cf la javadoc de ChannelPipeline.

    Il s'apparentent plus ou moins aux ServletFilters de JavaEE dans l'esprit.

  16. #16
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Merci pour tout.
    J'ai compris que ce sont les channels qui correspondent à la communication avec un client. Pour renvoyer un message à tous les clients j'ai vu les ChannelGroups qui sont très pratique mais ils ne permettent pas de renvoyer un messages a certains clients seulement.

    J'aimerais un dernier avis s'il te plait. Pour gérer les clients au mieux, est-ce une bonne idée de créer un classe Client avec comme attribut par exemple Pseudo, x, y, ip...Etc ET un attribut Channel contenant le channel correspondant.
    Dans la fonction Main, on défini un arrayList de type static contenant Chaque instance de Client. De ce fait lors de l'envoie d'un message il suffit de boucler l'arrayList, de selectionner le channel du client, et d'envoyer. Cela permettrait de gérer les messages privés..etc

    Merci encore,
    J'ai appris beaucoup de choses grâce à tes réponses, j'espère qu'elles en aideront d'autres.

    Mickaël

  17. #17
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    Bonjour à tous,

    ça fait un moment que je n'ai pas donné de nouvelles, j'étais en pleines expérimentations.
    Tout d'abord je tiens à vous remercier pour vos réponses qui m'ont grandement aidé.

    Ducoup voici l'architecture j'ai adopté :

    Un classe main : Elle lance le serveur et attends les nouvelles connexions
    Une classe ServeurHandler : Elle gère les nouvelles connexions et attribut une instance de la classe Player par client
    Une classe Player : Elle représente un joueur et possède différents attributs comme le pseudo, l'ip, le channel(Netty), la map sur lequel il est etc...
    Une classe PlayerHandler : Elle permet de rechercher un client(instance player) parmi tous les autres en donnant, le channel, l'ip, l'id ou même le pseudo. La classe permet aussi d'envoyer des données à un client, tous les clients, où tous sauf un.

    Une chose m'ennuie encore, une toute petite chose. Lorsque je veux récupérer tous les joueur de telle map, ma classe parcourt tous les joueurs et vérifie la propriété map. N'est-ce pas un peu lourd ? Si je désire les classer par map, n'y a t-il pas une solution plus souple que de créer un arrayList par map ?

    Enfin voilà où j'en suis, je remercie encore développez.com,
    Mickael

  18. #18
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Un classe Map qui contiendra une ArrayList de tous les joueur qui sont présents dessus...

  19. #19
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Mai 2011
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mai 2011
    Messages : 26
    Par défaut
    C'est exactement sur quoi j'étais entrain de me pencher
    Et bien que dire pour toute cette aide ? Merci beaucoup à toi sinok, tu m'as été d'une grande aide, je clos le sujet.

    Merci beaucoup !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Concevoir un serveur Java performant pour RIA Flash
    Par bokan dans le forum Général Java
    Réponses: 1
    Dernier message: 20/05/2011, 17h34
  2. Concevoir un serveur Java performant pour RIA Flash
    Par bokan dans le forum Dynamique
    Réponses: 0
    Dernier message: 19/04/2011, 13h33
  3. [Socket] Chaine entiere a envoyer a un serveur Java
    Par n8ken dans le forum Visual C++
    Réponses: 8
    Dernier message: 08/09/2006, 15h58
  4. [Socket] Probleme entre un Client C et un serveur JAVA
    Par bpy1401 dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 28/02/2006, 08h40
  5. [SOCKET] Client C connecté à un serveur Java
    Par missllyss dans le forum Développement
    Réponses: 2
    Dernier message: 07/06/2004, 13h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo