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 :

Discuter mon idée (Threads et sockets) pour les pro


Sujet :

Entrée/Sortie Java

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2011
    Messages : 17
    Par défaut Discuter mon idée (Threads et sockets) pour les pro
    Bonjour,

    Je vais vous expliquer un peu ma situation.

    J'ai un serveur en Java (TCP, en Multithreading) d'MMORPG qui supporte jusqu'à 2000 joueurs simultanément sans vraiment aucun problème. Sachant que chaque client connecté (en TCP) a son propre thread. Bon ok c'est pas une bonne architecture, mais pour le moment elle me va très bien (avec un serveur 64 bits de 6-cœurs, assez puissant).

    Dans mon code, j'ai une fonction static qui envoie les donnés à chaque client. Elle prends le PrintWriter du socket de chaque client, et écris dessus: (je résume dans cette fonction que j'ai simplifier):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static void send(Personnage player, String packet)
    {
    	PrintWriter out = player.get_socket().get_out();
    	out.print((packet)+(char)0x00);
    	out.flush();
    }

    Voila, cette fonction est appelée par n'importe quel thread (client) qui veut contacter un autre. Le seul problème que je rencontre avec cette fonction c'est dans:

    out.print((packet)+(char)0x00);
    out.flush();

    Parmi les 2000 clients que j'ai, (soit 2000 threads et 2000 sockets) il y a un seul socket au hasard qui finit par planter en quelques sortes, et à chaque fois qu'on lui écris avec un print() ou flush() il met trop de temps. Donc tout les threads qui ont tenter de print() et flush() sur le printerWriter de ce client vont en quelques sorts sleep pour plusieurs minutes.


    L'une de ces deux lignes (print/flush) mets des fois du temps pour finir. ça peut mettre des fois quelques minutes, entre 1 à 5 minutes, et des fois plus. J'ai pas arrêter de chercher l'origine de ce lag, mais je pense que c'est lié à l'os en lui même. J'ai windows server 2003 Et quand ce dernier atteins les 20Go dans la RAM (soit ~90% de sa RAM maximum) on commence à rencontrer des lags.
    Par exemple si on ouvre un dossier, ou on clique sur poste de travaille, ou on ouvre une application (exemple: notepad), on doit attendre entre 10secondes à 120 secondes (voir plus) des fois pour que ça s'ouvre.

    Je pense donc qu'il s'agit peut être de l'OS ? Bref, au lieu de me casser la tête pour chercher et vérifier le hardware avec mon hébergeur ou réinstaller l'OS etc, et finir par trouver que ça ne fix pas mon problème, j'ai décider de coder une class qui gère les packets d'une façon dynamique en plusieurs threads.

    Une class qui s'apelle par exemple: Packet_Buffer, avec des methods genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public void add_packet_to_liste(PrinterWriter envoyer_a_qui, String packet);
    public void envoyer_1_packet_dans_la_liste(); // sera appelé par des threads dispo
    et cette class aura à peu près 5 à 6 threads qui s'occuperont d'envoyer les packets aux clients.


    Le seul problème que je rencontre maintenant c'est: Et si les 6 threads ont finit par tous planter en même temps sur le PrinterWriter.flush(), mon serveur va donc complétement planter pour plusieurs minutes..

    Je cherche à savoir s'il existe une solution, peut être par exemple créer un autre thread unique qui tache à vérifier les 6 autres threads de la class, si l'un d'eux mets plus de 3 secondes, il le réinitialise ?

    ---
    Bref ce n'est qu'une idée que j'ai en tête, je pense qu'elle est peut être pas la meilleur idée, vue comme je débute en Java, mais j'aimerais avoir l'avis de pro pour me conseiller et donner d'autres idées s'il vous plait, maintenant que vous êtes au courant de ma situation.

    Ne me dites pas de refaire mon serveur avec du thread-pooling ou avec une biblio externe , je cherche juste une solution rapide et facile. J'ai pas le pouvoir ni le temps ni les compétences qu'il faut pour refaire le serveur à zéro.

    Merci d'avoir lu en tout cas.

  2. #2
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Par défaut
    Ah ouais, tout de même... Bon, je n'ai pas tout compris mais voici déjà quelques pistes.

    As-tu essayé les buffered ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    PrintWriter out = player.get_socket().get_out();
    BferedWriter br = new BufferedWriter(out);
    br.write("abcd123");
    ...
    Il faudrait que tu vérifies ta gestion d'exception sur les flush et les close.

    Autre piste, pourquoi gardes-tu ouverts les sockets ?

    Encore une autre piste, tu peux utiliser une sorte de timer. Quand le timer détecte que la transmission est trop longue, tu réinitialises le socket...
    Thierry Leriche-Dessirier
    Consultant Java JEE Web Agile freelance
    Rédacteur pour Developpez
    Professeur de Génie Logiciel à l'ESIEA

    Site : http://www.icauda.com / Linked'in : http://www.linkedin.com/in/thierryler / Twitter : @ThierryLeriche

  3. #3
    Membre expérimenté
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Par défaut
    C'est tes Thread d'envoi qui bloquent c'est ça?
    En fait tu gère bien un pool de 6 Thread, avec une queue de traitement classique: c'est ta liste d'envoi.
    Il faudrait effectivement mettre un time-out sur l'envoi.

    Pas besoin de bib externe en Java 6 ça existe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            threadPoolExecutor = new ThreadPoolExecutor( 6, 6, timeOutSeconds,
                TimeUnit.SECONDS,  new ArrayBlockingQueue<Runnable>( 2000) ) );
     
    puis threadPoolExecutor.execute( new Runnable(){
    public void run(){
    // faire le send ici
    });
    edit:
    du coup, plus besoin de gérer de liste et de Thread, c'est le ThreadPoolExecutors (et la bloquingQueue) qui le fait.

    d'ailleurs, sur la bloquingQueue, je ne suis pas sur d'avoir choisi la meilleure implem... mais ça marchera
    ref
    http://download.oracle.com/javase/6/...lExecutor.html

  4. #4
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2011
    Messages : 17
    Par défaut
    Citation Envoyé par thierryler Voir le message
    Ah ouais, tout de même... Bon, je n'ai pas tout compris mais voici déjà quelques pistes.

    As-tu essayé les buffered ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    PrintWriter out = player.get_socket().get_out();
    BferedWriter br = new BufferedWriter(out);
    br.write("abcd123");
    ...
    Il faudrait que tu vérifies ta gestion d'exception sur les flush et les close.

    Autre piste, pourquoi gardes-tu ouverts les sockets ?

    Encore une autre piste, tu peux utiliser une sorte de timer. Quand le timer détecte que la transmission est trop longue, tu réinitialises le socket...
    J'ai tester hier, mais ça n'a rien changer.

    --

    deltree, merci pour ta proposition, le pooling c'est pas mon point fort, je vais essayer quand même de monter quelques chose grâce à ton exemple, merci.

  5. #5
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Petite question en passant. Tu dis que lorsque la RAM atteint les 90% d'utilisation, tu observes ce probleme. Est ce que tu es sur que c'est toujours le cas (c'est à dire que ce serait la cause du probleme) ? Si oui, on peut (comme tu l'as fait) supposer que ca vient d'une charge trop importante (pour l'OS ou pour ton programme) donc il va peut etre falloir chercher une optimisation pour ne pas arriver à cette situation de saturation.

    Sinon, le comportement attendu en cas de lag (d'apres ce que j'ai compris, c'est lié à une socket donc à un joueur), c'est de fermer la socket ? Ou bien tu voudrais un comportement spécial ?

  6. #6
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    Avec 2000 threads en WAIT, ton processeur / OS / ordonnanceur doit passer son temps à chercher le prochain candidat à l'exécution, ou à "swapper" les processus/threads.

    As-tu un OS orienté Serveur (c'est-à-dire qui est prévu pour gérer un grand nombre de connection/socket simultanément ?)

    Autre piste, la carte réseau. Elle bufferise les paquets qu'elle reçoit et émet. Si son buffer est plein, elle refuse les paquets et les processus sur ta machine (le driver) "attende" une place dans la file.

    +1 sur la mise en place d'un système de timeout sauf qu'il ne faut pas setter le timeout dans le constructeur (qui est le temps pendant lequel le thread poolé est gardé en vie sans exécuter de tâche) mais à la soumission de la tâche via invokeAll, invokeAny ou lors de l'attente du résultat via get.
    Il restera à gérer l'annulation !
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  7. #7
    Membre éclairé
    Profil pro
    Architecte logiciel
    Inscrit en
    Janvier 2006
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Architecte logiciel
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2006
    Messages : 28
    Par défaut
    Juste une remarque, si plusieurs thread (client) essaye en meme temps d'ecrire dans le meme "out", ca peut etre tres vilain, je te conseil de synchroniser les acces concurents. (sur out, ou sur la socket issue de la fonction getSocket() par exemple).

    et autre remarque, multiplier les threads (surtout au dela du nombre de processeur) n'est pas toujours une optimisation pour traiter plus vite ou limiter les collisions, au contraire.

    pour ton probleme de thread par client, tu ne pourras changer ton architecture qu'en passant par les nio (dans java), et c'est pas forcement évident si tu es un peu debutant sur ce genre de problemes.

  8. #8
    Membre émérite Avatar de JoeChip
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    536
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 536
    Par défaut
    Pourquoi la mémoire se remplit-elle autant ? il y a peut-être un memory leak ? Si non, pourquoi ne pas simplement augmenter la mémoire (physique) ?

    Je ne pense pas que mettre une procédure genre "dépanneur" soit une bonne idée ; je commencerais par refactoriser le code le plus gourmand en mémoire, histoire de voir si je ne peux pas optimiser ça.

    Dans tous les cas, je changerais l'OS ; je doute que windows 2003 (c'est un win2k tardif ?) soit le meilleur choix. Un linux adapté (basé sur une Debian ou une Slackware ?) augmenterait les performances ; à mon avis, même XP serait plus efficace.

Discussions similaires

  1. Les IDE sont-ils dangereux pour les développeurs ?
    Par Cedric Chevalier dans le forum Actualités
    Réponses: 85
    Dernier message: 13/05/2014, 11h41
  2. [WD10] une idée ! (pour les pro)
    Par doji_lemaitre dans le forum WinDev
    Réponses: 8
    Dernier message: 08/05/2012, 18h40
  3. Réponses: 3
    Dernier message: 05/04/2006, 15h13
  4. [VB6] Pour les pro de VB, recup et modifier le workgroup
    Par manshivas dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 25/03/2006, 18h52
  5. Réponses: 3
    Dernier message: 14/12/2005, 23h08

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