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

C++ Discussion :

[Réseau] Ecoute de port et connections simultanée


Sujet :

C++

  1. #1
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut [Réseau] Ecoute de port et connections simultanée
    Bonjour,

    J'aimerais réaliser un programme gérant les accès à un serveur. Mon soucis ne vient pas directement du C++, mais plutot d'un problème théorique :

    Mon programme écoute un port donné. Lorsqu'il reçoit quelque chose, il traite la demande en direct : en gros il reçoit un identifiant, et un mot de passe, il vérifie dans la BDD s'il existe, puis retourne un résultat au client.

    Ma question est de savoir ce qu'il arrive, si pendant ce traitement, une ou plusieurs autres demandes arrivent? Seront-elles mises dans une file d'attente (un genre de pile FIFO) automatiquement par le système, ou au contraire ces demandes seront elles simplement ignorées, tant que le traitement de la première demande n'est pas terminé?

    Quelle solution apporter? Mettre un thread qui ne fait qu'écouter le port en permanance, et ajouter le pointeur vers cet ordinateur dans une pile manuellement? Mais le soucis est toujours le même si d'autres demandent arrivent pendant ce temps (en cas de très forte affluance).... Mettre plusieurs threads écoutant plusieurs ports? Mais encore faudrait-il que le client sache quel port est disponible...

    Qu'en pensez-vous?

    Je sais que le temps de traitement étant très court (quelques fractions de secondes), le problème ne devrait pas se produire très souvent. Cependant, j'aimerais savoir s'il est possible que cela arrive, et s'il on peux l'éviter.

    Merci d'avance pour vos réponses!

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Les connexions non satisfaites sont mises en file d'attente, selon le second paramètre de listen().
    Au-delà, je ne sais pas ce qui est censé se passer: Peut-être que la connexion est explicitement refusée, ou que le serveur ne répond simplement pas (poussant le connect() à réessayer automatiquement jusqu'au timeout)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Pour ce genre de situation, il y a bien une architecture optimale.
    Celle-ci consiste mettre en place un thread qui attend de nouvelles connexions. Lorsqu'il y a une demande qui arrive, il passe la socket client à un thread faisant partie d'un pool de thread. Un pool de thread en gros c'est un nombre limité de threads qui tournent en permanence. On peut en réserver un mais il ne sera à nouveau disponible que quand il aura terminé sa tache. Cette solution présente le double avantage multi utilisateur+limitation du nombre de connexions (indispensable pour un serveur résistant).
    Bon, même si c'est ce qu'il y a de mieux, ce n'est pas forcément simple à faire
    Alors je te propose deux autres solutions:
    - Même principe que plus haut mais il n'y a pas de pool. C'est à dire que pour chaque connexion entrante un thread est créé. Généralement pour des dossiers scolaires ça fonctionnera toujours bien.
    - Un serveur monothread. Le serveur reçoit une demande, fais le traitement et renvoie la réponse. En dehors du fait que c'est la pire solution point de vue performance, il est impératif que ton protocole soit déconnecté, c'est à dire qu'il n'ait aucun besoin de maintenir une connexion permanente (donc comme http mais pas du tout comme ftp). Et oui, si une demande arrive pendant que ton serveur traite une autre demande elle sera mise en attente. Il n'y a que l'hote distant qui pourra décider de laisser tomber si le délais d'attente est trop long (une dizaine de secondes, ça ne signifie pas qu'il soit agréable pour l'utilisateur d'attendre dix secondes!).
    PS: laisse tomber cette idée de plusieurs ports, on a tous fait ce genre d'erreur de conception au début mais avec le recul c'est vraiment ridicule.

  4. #4
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    Merci pour vos réponses.

    Pour résumer la "meilleure" solution :
    - 1 thread s'occupe d'écouter un port
    - Ce thread principal ajoute la socket à une liste des demandes en attente (liste accessible à partir des autres threads)
    - x threads s'occupent de traiter 1 à 1 chaque demande listée dans cette liste.

    On est bien obligé de passer par une liste non? Tu n'en parles pas, mais je suppose que ce serait plus simple que de devoir à chaque fois trouver un thread disponible (sans parler du cas à prévoir si tous les threads sont déjàs occupés)...


    Par contre tu disais qu'en terme de performance, un monothread était la pire solution, mais je ne vois pas pourquoi : je connais le principe du thread, qui est de réaliser des actions en parallèle. Par contre, en terme de performance, je doute qu'il y aie un gain : entre 3 threads qui tournent en permanance et donc se partagent en trois la puissance de calcul du processeur, et dont il faut du temps pour switcher entre chaque thread, et 1 seul utilisant tout la puissance de calcul du processeur, et sans temps de switch, l'avantage reviendrait logiquement au monothread
    Idem en termes de mémoire : un seul thread consommera moins de mémoire vive que 3 tournant en permanance

    Ai-je mal compris quelque chose?

  5. #5
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Par défaut
    Il faut bien comprendre que dès que l'on fait intervenir des threads, il y a des difficultés importantes qui arrivent (il faut que l'application soit multithread safe).

    Si les traitements clients a effectués sont légers, il est possible d'utiliser un select sur l'ensemble des sockets et d'avoir une application monothread performante.

    Par contre, dès qu'il y a des traitements lourds (par exemple envoi d'un fichier, attente pendant un certain temps), il est conseillé de faire intervenir un thread à ce moment lent.

    Souvent, les gens ne se prennent pas la tête et font un thread par client : il est toujours possible de limiter le nombre de client pour éviter que l'application rame (donc le nombre de thread).


    Il faut savoir que contrairement au processus, le basculement entre deux threads est nettement plus rapide qu'entre deux processus (d'un ordre de 30 je crois), donc ce n'est pas vraiment un soucis.

    Faire intervenir des threads peut également simplifier conceptuellement l'application.


    A toi de voir

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Citation Envoyé par ChriGoLioNaDor Voir le message
    On est bien obligé de passer par une liste non? Tu n'en parles pas, mais je suppose que ce serait plus simple que de devoir à chaque fois trouver un thread disponible (sans parler du cas à prévoir si tous les threads sont déjàs occupés)...
    Tout dépend de la conception du pool de thread, que l'on concevra généralement de manière générique. Il peut par exemple être fait, comme tu le suggère, avec une queue de taille limitée, la on a pas vraiment une limite du nombre de connexion mais du nombre de demandes, et on repart dans le protocole déconnecté. Un pool de thread simple avec limite du nombre de connexions sera en général fait en jouant avec des mutex/sémaphores.

    Citation Envoyé par ChriGoLioNaDor Voir le message
    Par contre tu disais qu'en terme de performance, un monothread était la pire solution, mais je ne vois pas pourquoi : je connais le principe du thread, qui est de réaliser des actions en parallèle. Par contre, en terme de performance, je doute qu'il y aie un gain : entre 3 threads qui tournent en permanance et donc se partagent en trois la puissance de calcul du processeur, et dont il faut du temps pour switcher entre chaque thread, et 1 seul utilisant tout la puissance de calcul du processeur, et sans temps de switch, l'avantage reviendrait logiquement au monothread
    Idem en termes de mémoire : un seul thread consommera moins de mémoire vive que 3 tournant en permanance

    Ai-je mal compris quelque chose?
    Tu te trompes, tu ne vois pas toutes les subtilités. Ta logique serait bonne si le role d'un serveur était de recevoir de petites données, faire de gros calculs dessus et puis renvoyer une petite réponse. Je ne dis pas que ça n'existe pas, mais en général on se servira d'une calculatrice pour ça .
    Le plus souvent un serveur a pour but de distribuer ou de stocker des informations, à partir de fichier pour les cas simples, d'une base de données la plupart du temps. C'est à dire que le temps de calcul ne vaut pas le centième du temps transfert client->serveur+transfert serveur->bd+temps de traitement bd+transfert bd->serveur+transfert serveur->client. Un serveur passe la plupart de son temps à attendre, d'où l'utilité du multithread, parcequ'un thread qui attend ne ralentis pas les autres.
    Qui plus est, il faut penser à tous les utilisateurs. Il est bien plus équitable d'avoir 10 utilisateurs simultanés qui recoivent leur réponse en même temps plutot que de faire attendre éternellement ceux qui ont eu le malheur d'arriver en dernier. Imagine un serveur ftp, avec de gros fichiers qui prennent plusieurs heures pour le transfert, tu imagines si tu devais attendre aussi longtemps avant que la reception de ton fichier ne commence?

  7. #7
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    Oui en effet, en cas de traitement long (transfert de gros fichiers par exemple, ou encore attente d'une réponse du client), ou d'actions simultanées (on veux pendant le transfert afficher une barre indiquant le pourcentage d'avancement), le multithread est obligatoire ou presque.

    Je parlais surtout de mon cas : un programme autonome qui ne s'occupe que de recevoir login+mdp, fait une recherche dans une BDD pour savoir si tout est OK, puis renvoie une réponse (par exemple un identifiant unique, ou tout simplement un booléen). Il n'y a donc aucun traitement long, à part à la limite l'accès à la BDD, qui se fait en local.

    Dans ce cas précis, je serais plutot contre la création d'un thread par client : le temps de sa création et de sa destruction risque de ne pas être négligeable par rapport au temps d'exécution...

    Par contre en effet, la création de x threads permanants et d'un thread "d'écoute" pourraient être une autre solution envisageable, mais j'essaie justement de voir s'il y aurait un gain réel dans ce cas précis. Mais d'un coté, il est vrai que cela permettrait aussi de ne pas bloquer le programme en cas de soucis avec un client (transfert des données anormalement lent, mauvaise communication, ...).


    PS : je vais réviser mes mutex/sémaphores. Je connais ces termes, mais ne me rappelle plus leur utilité précise, depuis le temps ^^. C'est bien ce qui permet de créer des sections critiques (par exemple pour accéder et modifier les données de ma liste) ? :p

  8. #8
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Les Mutex permettent à des Thread différents d'accéder à des mêmes ressources de manière "safe".
    Peut etre as-tu déjà choisi une solution? Sinon il y a Boost.Thread qui implémente thread Et mutex.
    Tu trouveras des tutos ICI (Miles)

    A +

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Ecoute, tu fais ce que tu veux, mais les méthodes de création de serveur sont bien connues depuis des lustres. Va demander à n'importe qui connaissant un peu le sujet et il te parlera toujours des deux approches suivantes:
    - pool de threads: sauf exceptions incroyablement rares, c'est the meilleur dans tous les cas. L'optimisation réside dans la conception du pool.
    - threads à la demande: pas hyper résitants face à des centaines d'utilisateurs ou aux vilains pirates qu'on rencontre dans la vrai vie mais un bon rapport simplicité/efficacité.
    Les deux sont adaptables à tous les types de protocole.
    Mais franchement, un serveur monothread tu peux retourner ça dans tous les sens ce sera toujours nul. Le seul interet est qu'il est un peu plus simple à concevoir, à toi de voir si l'ignorance est une bonne excuse.

  10. #10
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    Si je voulais rester dans l'ignorance, je n'aurais pas posé de question sur le forum J'essaie justement de comprendre afin de progresser ! Car faire sans comprendre, ce n'est pas ça non plus.

    Cela dit, tu m'as convaincu avec ton pool de thread Tu n'aurais pas par hasard de doc concernant la création (et l'optimisation) de ce pool?

    En attendant je vais voir avec mon ami Google (et recherche du forum ^^) ce que je peux trouver.

    Dans tous les cas, merci pour vos explications!

  11. #11
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    La dernière fois que j'en ai fait un, c'était il y a deux ans, alors ça date un peu. Mais je vais quand même essayer de te filer un coup de pouce au feeling.
    J'imaginerais bien un système avec un mutex par thread (initialisé à unlocked), un booléen de disponibilité par thread (à true) et un sémaphore (initialisé au nombre de threads).

    Lorsque le serveur veut lancer un thread, il décrémente le sémaphore et teste les threads un à un pour en trouver un disponible. Pour cela il verouille le mutex d'un thread et regarde son booléen de disponibilité. Si le thread n'est pas disponible il déverouille le mutex et passe au suivant. Si le thread est disponible il fait passer le booléen indiquant la disponibilité à false, demande au thread de s'occuper de la connexion puis déverouille le mutex.
    Lorsqu'un thread termine sa tache, il verouille son mutex, fait passer son booleen de disponibilité à true, déverouille son mutex puis incrémente le sémaphore.

    Dites le moi si il y a une faille ou plus simple
    A noter que je parle ici de sémaphores au sens conceptuel, pas au sens "posixien"
    En dehors de ça, l'interet d'un pool de threads est aussi d'économiser le cout de création/suppression d'un thread, en lançant tous les threads à l'avance et en les faisant "patienter". Le meilleur moyen pour qu'un thread attende sans prendre de temps processeur est de le faire bloquer sur... un mutex. Donc si tu veux procéder de cette manière, il te faudra un mutex de plus par thread (donc au total 2 mutexs par thread) initialisé à locked. Dés son lancement le thread le verouille (donc il se retrouve bloqué). Lorsque le serveur décide de réveiller le thread il déverouille le mutex (le thread repart). Tout à la fin de son traitement, après avoir incrémenté le sémaphore, le thread verouille le mutex et se retrouve dans le même état qu'au départ.

  12. #12
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    Je vois le principe

    Bon, je vais essayer de mettre ça en place! Ca fait un bon 2 ans que je n'ai pas programmé en C++, je vais rigoler ^^

    Merci beaucoup de votre aide, elle m'a permise de comprendre quelques petites choses

  13. #13
    Membre averti
    Inscrit en
    Mai 2007
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 26
    Par défaut
    Je ne suis pas sur qu'un serveur monothreadé soit une si mauvaise idée, surtout si c'est pour uniquement faire une requete de login.

    Les serveurs monothreadé ont l'avantage d'etre très peu gourmant en terme de ressource système en témoigne les serveurs tels tHttpd.

    Si tu veux passer sur une archi multi-thread avec un pool de thread je te conseil de jeter un coup d'oeuil à Boost.Asio , il y a un exelent exemple sur le CVS avec un pool de thread très facile à mettre en place.

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    En fait il y a pas 36 solutions. Chaque solution a ses avantages et ses inconvéniants:

    1. Utilisation du même et unique thread:
    - Facile à implémenter les piles réseaux se chargeant de mettre en attente les demandeurs non satisfaits immédiatement.
    - Une unique connection à la database (utilisée par LE thread).

    2. Création d'un thread à chaque demande:
    - La création d'un thread est lourde, est doit être rajoutée au temps de traitement. Si le traitement est court (ce qui est le cas ici), il est loin d'être négligeable.
    - La connection à la database doit passer par un pool de connections (on ne fait pas impunément 1000 connections simultannées à la DB). Il faut donc implémenter un système de pool pour les connections DB.

    3. Création d'un pool de thread:
    - La création des N threads se fait à l'initialisation (et donc n'est pas rajoutée aux temps de traitement).
    - Chaque thread a sa propre connection à la database (et le nombre est bien limité), le pool étant géré au niveau du thread.


    En terme de temps de codage, 2 est équivalent à 3 (puisqu'il faut un 'pool' dans les deux cas), et 2 est vraiment inférieur à 3 en terme de performances. Voilà pour ce qui est de la solution "je crée un thread à chaque demande".

    Il ne reste donc que 1 et 3...
    Si la requête à la DB est vraiment courte, 1 peut largement suffire.
    Si la requête à la DB peut être longue (genre > 10ms), alors la solution 3 s'impose.

  15. #15
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Avec un pool de threads, on peut très bien limiter le nombre de connexions à 1. On a donc une applic adaptable selon les gouts avec de simples fichiers de configuration.
    Et pour ce qui est de la connexion à la bd, il y a aussi un truc génialissime qu'on appelle... un pool de connexions Et la crois moi sur parole ça fait gagner en vitesse comme c'est pas croyable (même avec une seule connexion en simultané sur un serveur local, l'économie sur le temps de connexion/déconnexion se mesure en secondes).

    En dehors de ça, la nuit porte conseil alors j'ai pensé à un moyen plus simple et plus optimisé pour implémenter le pool de threads si tu ne comptes pas en prendre un tout fait.
    On utilise un sémaphore (toujours initialisé au nombre de threads), un buffer destiné à contenir un message à destination des threads, un unique mutex pour protéger le buffer (à unlocked) et un unique mutex pour bloquer tous les threads (à locked). Déja ça fait moins de mutexs
    Lorsque le serveur veut passer un message à un thread il décrémente le sémaphore, lock le mutex du buffer, met son message dans le buffer puis unlock le mutex des threads. Et c'est tout.
    Du coté des threads, au démarrage ils lock tous le mutex des threads (ils se retrouvent tous bloqués). Après que l'un d'entre eux ait été débloqué il va retirer le message du buffer puis unlock le mutex du buffer. A la fin de son exécution il incrémente le sémaphore puis retourne bloquer sur le mutex des threads.
    Il faut penser à prévoir un type de message pour dire au thread "arrète toi".

    Voila, en réalité c'est très proche du principe d'une queue, avec seulement une place. Ce que je n'aime pas avec une queue à plusieurs places c'est qu'un objet peut se retrouver bloqué très lontemps. Or dans un serveur cet objet contiendra généralement une socket client, donc le client voit que sa connexion a été acceptée par le serveur mais il ne reçoit aucune réponse. Avec cette architecture, le serveur peut très bien faire un decrement conditionnel sur le sémaphore, si ça rate il ferme la connexion client ou envoie un message "too much connections". Néanmoins, pour un protocole déconnecté et rapide comme le tiens, une queue à plusieurs places pourrait être satisfaisante.

  16. #16
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    J'ai aussi réfléchi de mon coté à la création de mon petit programme. Voici ce que je pensais faire pour gérer les connections :

    On a une queue à laquelle un mutex (M1) lui est associée, et un second mutex (M2) servant à savoir s'il y a ou non des clients en attente (locked au démarrage).

    - Un premier thread s'occupe d'écouter le port. Dès qu'il reçoit un message, il lock M1, ajoute le socket client à la queue, et unlock les 2 mutex. Ensuite il recommence son cycle.

    - Chaque autre thread créé au démarrage de l'appli bloque sur M2. Dès qu'il est débloqué, il lock M2 à nouveau, et bloque sur M1. Une fois débloqué il le lock, retire un socket client, et unlock M2 si la queue n'est pas vide. Ensuite il unlock M1 et recommence son cycle.


    Avec ça, pas besoin de message pour dire au thread "arrête toi", puisque les threads bloquent sur M2 qui n'est débloqué que lorsqu'il y reste au moins 1 demande en attente.

    Biensûr on peux rajouter un sémaphore pour limiter la taille de la queue, et éviter d'avoir 500 connections en attente (pas forcément limité au nombre de thread, mais par exemple à 20 connections, nombre modifiable dans un fichier de config)

  17. #17
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Quelques remarques:
    Citation Envoyé par ChriGoLioNaDor Voir le message
    - Chaque autre thread créé au démarrage de l'appli bloque sur M2. Dès qu'il est débloqué, il lock M2 à nouveau
    C'est pas très clair, je supposerais que les threads client font un simple M2.lock()
    Citation Envoyé par ChriGoLioNaDor Voir le message
    ..., et bloque sur M1. Une fois débloqué il le lock, retire un socket client, et unlock M2 si la queue n'est pas vide. Ensuite il unlock M1 et recommence son cycle.
    Arg, non, il ne faut surtout pas qu'un thread client unlock M2, ça aura pour effet de libérer un autre thread alors qu'il n'y aura peut-être aucune connexion en attente. Il n'y a que le serveur qui peut unlocker ce thread, et que les clients qui peuvent le locker.

    Pour ta liste fifo le comportement varie suivant la façon dont elle est conçue:
    - elle est de taille infinie, c'est le cas le plus facile, tu ne changes rien, mais c'est pas ce qu'il y a de plus résistant
    - elle est de taille finie, tout d'abord, penser à l'implémenter comme un tableau (plus rapide). Le thread serveur doit pouvoir s'apercevoir si la limite est atteinte et dans ce cas il jette la connexion et n'unlock pas M2.
    Pour le message "arrete toi", tu n'as pas compris. Ce n'est pas pour mettre le thread en attente, c'est pour le tuer lorsque tu éteinds l'ordi tout simplement et tu en as besoin.
    Pour la taille de ta liste, tu n'as pas besoin d'un sémaphore, tu peux juste faire la vérification dans la zone protégée par M1 à moins que tu ne veuilles que le serveur bloque tant qu'il n'y a pas de places. Et idéalement il faudrait que la taille soit au moins égale au nombre de threads.

  18. #18
    Membre confirmé
    Inscrit en
    Août 2005
    Messages
    177
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 177
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    - Chaque autre thread créé au démarrage de l'appli bloque sur M2. Dès qu'il est débloqué, il lock M2 à nouveau
    C'est pas très clair, je supposerais que les threads client font un simple M2.lock()
    En effet, chaque thread fait un M2.lock() ^^ J'aime compliquer les choses.


    ..., et bloque sur M1. Une fois débloqué il le lock, retire un socket client, et unlock M2 si la queue n'est pas vide. Ensuite il unlock M1 et recommence son cycle.
    Arg, non, il ne faut surtout pas qu'un thread client unlock M2, ça aura pour effet de libérer un autre thread alors qu'il n'y aura peut-être aucune connexion en attente. Il n'y a que le serveur qui peut unlocker ce thread, et que les clients qui peuvent le locker.
    Si justement, j'ai bien précisé qu'il unlock M2 SI LA QUEUE N'EST PAS VIDE, une fois qu'il a retiré son socket. Il y aura donc forcément au moins 1 connection en attente.

    En gros quand un thread client retire une donnée de la queue, il dit au suivant qu'il peut se lancer, seulement s'il y a encore du boulot pour lui. Le thread d'écoute lui ne sert qu'à dire au 1e thread client de se lancer, dans le cas (comme au démarrage de l'appli) où tous les threads sont en attente.

    Dans le cas justement où il ne reste qu'une seule connection en attente, dès que M2 est débloqué (lorsque le thread principal ou un autre thread client l'aura débloqué), un thread client va bloquer M2, puis M1, retirer cette connection en attente de la queue, et vérifier si elle est vide. Etant vide, il ne débloquera pas M2 (donc pas d'autre thread lancé, ce sera au thread principal de le faire lorsqu'il rajoutera une connection à la queue), débloque M1, puis recommence son cycle (lock M2 etc)


    Pour ce qui est de la limitation de la queue, un simple compteur ou un sémaphore pourra très bien faire l'affaire (sémaphore si on veux attendre qu'une place se libère pour rajouter la connection, compteur sinon).


    Idem pour "arrête toi", il faudra en effet tuer les threads lorsque l'appli s'arrête afin d'éviter les fuites mémoire (pas lorsque tu éteints ton ordinateur, je doute que ton thread survive en mémoire vive une fois l'ordi arrêté )


    Je réédite ma vision du pool, version "plus claire" (enfin j'espère)

    - Un premier thread s'occupe d'écouter le port. Dès qu'il reçoit un message, il lock M1, ajoute le socket client à la queue, et unlock M1 puis M2. Ensuite il recommence son cycle.

    - Chaque autre thread client lock M2, puis M1. Ensuite il retire un socket client, et unlock M2 uniquement si la queue n'est pas vide, puis unlock M1 et recommence son cycle.

  19. #19
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    D'accord, je vois. Effectivement avec une file d'attente il vaut mieux faire comme ça. Par contre, à mon avis il y a quelques chances pour qu'un thread soit débloqué même si il n'y a rien sur la file, mais dans ce cas il suffit de l'envoyer reblocker sur M2.
    Citation Envoyé par ChriGoLioNaDor Voir le message
    Pour ce qui est de la limitation de la queue, un simple compteur ou un sémaphore pourra très bien faire l'affaire (sémaphore si on veux attendre qu'une place se libère pour rajouter la connection, compteur sinon).
    C'est exactement ce que je dis.
    Citation Envoyé par ChriGoLioNaDor Voir le message
    Idem pour "arrête toi", il faudra en effet tuer les threads lorsque l'appli s'arrête afin d'éviter les fuites mémoire (pas lorsque tu éteints ton ordinateur, je doute que ton thread survive en mémoire vive une fois l'ordi arrêté )
    Hum, ça c'est si il y a une panne de courant. Il est bien entendu evident qu'un bon serveur doit être capable de capter un message du système d'exploitation pour savoir si il doit s'éteindre, que ce soit parceque tu as envoyé le message toi même ou parceque la séquence de cloture du système a été enclenchée. La raison pour laquelle il faut leur demander de se terminer n'est pas tant d'économiser les fuites mémoires (si le processus se ferme on s'en fout un peu) que de ne pas fermer brutalement les connexions.
    Si ton protocole est déconnecté, tu peux capter cet appel uniquement dans le thread serveur, qui va arreter d'écouter et envoyer autant de messages "arrete toi" dans la file qu'il y a de threads, comme ça on purge les demandes en cours mais tous les threads finissent par mourir. Si il est connecté il faut en plus que tous les threads puissent capter ce signal et envoyer un message "fin de connexion" au client.

Discussions similaires

  1. Ecouter un port sur un réseau
    Par zouheir dans le forum Entrée/Sortie
    Réponses: 12
    Dernier message: 16/08/2006, 02h03
  2. Réseau local par ports usb ?
    Par progfou dans le forum Hardware
    Réponses: 3
    Dernier message: 17/03/2006, 20h59
  3. [Système] Ecouter un port serveur Java
    Par sozie9372 dans le forum Langage
    Réponses: 3
    Dernier message: 19/01/2006, 21h35
  4. Ecouter le port de téléphonie sur IP
    Par WOLO Laurent dans le forum Développement
    Réponses: 6
    Dernier message: 24/09/2005, 12h43
  5. [UDP][Socket] perte de paquets et arret d'ecoute sur port
    Par Guismo1979 dans le forum Développement
    Réponses: 6
    Dernier message: 02/01/2003, 12h13

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