Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Serveur multithread

16 réponses
Avatar
Flowent
Bonjour,

Voilà je veux faire une petite liste de diffusion personnel :) (comme sympa)
j'ai donc chercher comment faire un serveur en c++, cependant je me heurte à
quelques questions dont je ne trouve pas de solution
-> Vaut il mieux un thread par client, des qu'un client se connecte, hop un
nouveau thread
-> ou plutot un thread par tâche :
- un thread qui attent les clients et les stockes dans une
liste, parcours la liste et si un client a qqchose à dire, il le traite
(utilisation de select/poll) (traitement : connexion a une base de donnees,
recuperation des abonnees, envoi de mails aux abonnées)
- un thread qui envoi les mails
- un thread qui attends les mails du serveur SMTP

Je precise que je suis sur monoprocesseur, la vitesse d'une commande faite
au serveur ne depassera pas les 30ms (le temps de la reconnaitre,
l'executer, envoyer une commande au thread mail, envoyer la reponse ).
Je ne fais aucune supposition sur le nombre de connecté qu'il peut y avoir
simultanément (aussi bien 1 que 2000...)
Je cherche une bonne METHODE pour implementer mon serveur..

merci

10 réponses

1 2
Avatar
Patrick 'Zener' Brunet
Bonjour.

Je réponds à Flowent
Bonjour,

Voilà je veux faire une petite liste de diffusion personnel :) (comme
sympa) j'ai donc chercher comment faire un serveur en c++, cependant
je me heurte à quelques questions dont je ne trouve pas de solution
-> Vaut il mieux un thread par client, des qu'un client se connecte,
hop un nouveau thread
-> ou plutot un thread par tâche :
- un thread qui attent les clients et les stockes
dans une liste, parcours la liste et si un client a qqchose à dire,
il le traite (utilisation de select/poll) (traitement : connexion a
une base de donnees, recuperation des abonnees, envoi de mails aux
abonnées)
- un thread qui envoi les mails
- un thread qui attends les mails du serveur SMTP

Je precise que je suis sur monoprocesseur, la vitesse d'une commande
faite au serveur ne depassera pas les 30ms (le temps de la
reconnaitre, l'executer, envoyer une commande au thread mail,
envoyer la reponse ).
Je ne fais aucune supposition sur le nombre de connecté qu'il peut y
avoir simultanément (aussi bien 1 que 2000...)
Je cherche une bonne METHODE pour implementer mon serveur..



C'est pas trop un problème de C++, plutôt de pure programmation...

Les deux solutions ont avantages et inconvénients. En gros:
1) soit vous stockez vos opérations en attente dans des files d'attente
faites de "records" et vous les épongez avec des threads coordonnés
effectuant des tâches complémentaires,
2) soit vous stockez chaque séquence d'opération dans le contexte d'un
thread pour la "mécaniser" globalement.

Prenez en compte aussi la robustesse face aux imprévus:
- Client ne respectant pas le protocole de transaction,
- Attentes dues aux autres services,
- Déconnexions intempestives...

La solution 2) est plus simple a priori parce qu'elle conduit à une
programmation purement séquentielle, mais vous pouvez vous retrouver avec
des threads plus ou moins bloqués et en surnombre, et là vous devrez choisir
entre:
- les tuer sauvagement en perdant tout leur contexte,
- extraire ce contexte pour le traiter en erreur, ce qui revient finalement
à la solution 1).

La solution 1) fixe le nombre de threads, par contre elle vous oblige à
segmenter les opérations (c'est presque de l'événementiel) et à gérer des
capacités relatives de traitement. Elle réclamera aussi plusieurs zones de
partage+synchronisation inter-threads bien distinctes, ce qui multiplie le
risque de deadlock en cas d'erreur de conception (méfiez-vous notamment des
librairies qui ne seraient pas thread-safe).

Mais ça se fait et c'est sympa :-)

Cordialement,

--
/***************************************
* Patrick BRUNET
* E-mail: lien sur http://zener131.free.fr/ContactMe
***************************************/

Avatar
kanze
Flowent wrote:

Voilà je veux faire une petite liste de diffusion personnel :)
(comme sympa) j'ai donc chercher comment faire un serveur en
c++, cependant je me heurte à quelques questions dont je ne
trouve pas de solution
-> Vaut il mieux un thread par client, des qu'un client se
connecte, hop un nouveau thread


C'est la solution classique dans les protocols où il y a une
session -- en général, quand on se sert de TCP (au moins que le
temps de connexion soit très court, comme c'est typiquement le
cas avec SMTP ou HTTP). Si le client peut agir de façon
asynchrone (c-à-d qu'il peut envoyer encore une requête sans que
le serveur a fini avec la précédante), on pourrait même
considérer deux threads par connexion, un pour la lecteur, et un
autre pour l'écriture. Voire trois ou plus, avec des threads
pour le véritable travail.

-> ou plutot un thread par tâche :

- un thread qui attent les clients et les
stockes dans une liste, parcours la liste et si un client a
qqchose à dire, il le traite (utilisation de select/poll)
(traitement : connexion a une base de donnees, recuperation
des abonnees, envoi de mails aux abonnées)


Il faut de toute façon quelques threads supplémentaires, selon
le protocol. Au minimum, si tu as un thread par connection.

- un thread qui envoi les mails
- un thread qui attends les mails du serveur SMTP

Je precise que je suis sur monoprocesseur, la vitesse d'une
commande faite au serveur ne depassera pas les 30ms (le temps
de la reconnaitre, l'executer, envoyer une commande au thread
mail, envoyer la reponse ).


Et quelle est la quantité de requêtes en entrée ? À premier
abord, je me démande même s'il faut du multithreading ; tu
attends un email, tu le traites (dans le même thread), et tu te
remets en attente. Celui qui envoie l'email attendra bien 30ms
pour la connexion SMTP.

Je ne fais aucune supposition sur le nombre de connecté qu'il
peut y avoir simultanément (aussi bien 1 que 2000...)


Sauf que si tu te présentes comme serveur SMTP, la durée de la
connexion ne doit jamais dépasser le temps d'envoyer un seul
email. (En principe, on peut rester connecté en SMTP pour une
durée illimitée. Dans la pratique, on ne l'est que le temps
d'envoyer les emails présents. Et quelqu'un qui se connecte à
ton serveur ne va pas avoir des centaines d'email pour lui.)

Je cherche une bonne METHODE pour implementer mon serveur..


Le plus simple, c'est de faire tout dans un seul thread, avec
une simple boucle : reception, traitement, envoie. Si la risque
de blocage dans une connexion paraît trop grande, je ferais un
*processus* par connexion, avec un processus à part qui attend
des connexions.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Flowent
Merci, voici quelques precisions : j'ai un serveur fait en c++ (par moi) et
le serveur SMTP (postfix)
Mon serveur accepte quelques commandes (LIST, GET...)

Exemple avec un thread par "tâche" donc 2 threads un pour les mails, un pour
discuter avec le client :
quand le client envoi LIST :
- le serveur parcours la liste des client et voit qu'un client a qqchose
à dire, il reconnait la commande, se connecte a la BDD, recupere la liste,
prepare le mail et l'ajoute a la liste des mails à envoyer du thread mail,
puis on reponds au client : "mail envoyé"
- la thread mail prend la liste des mails à envoyer et les envois (en se
connectant à postfix).


merci
voilà pour le fonctionnnement du serveur

Cela change t'il qqchose?
Avatar
loufoque

Voilà je veux faire une petite liste de diffusion personnel :) (comme sympa)
j'ai donc chercher comment faire un serveur en c++, cependant je me heurte à
quelques questions dont je ne trouve pas de solution


Le mieux est de ne pas utiliser de threads du tout et de faire du
traitement asynchrone.

Par exemple, le serveur HTTP lighttpd qui est plus performant qu'apache.

Avatar
Flowent
"loufoque" a écrit dans le message de news:
43e4fa16$0$11084$
Le mieux est de ne pas utiliser de threads du tout et de faire du
traitement asynchrone.

Par exemple, le serveur HTTP lighttpd qui est plus performant qu'apache.


qu'entend tu par traitement asynchrone ?

Avatar
Flowent
"loufoque" a écrit dans le message de news:
43e4fa16$0$11084$
Le mieux est de ne pas utiliser de threads du tout et de faire du
traitement asynchrone.

Par exemple, le serveur HTTP lighttpd qui est plus performant qu'apache.


qu'entend tu par traitement asynchrone ?

Avatar
loufoque

qu'entend tu par traitement asynchrone ?


Utilisation de select, poll, /dev/poll, epoll ou kqueue.

Avatar
kanze
Flowent wrote:
Merci, voici quelques precisions : j'ai un serveur fait en c++
(par moi) et le serveur SMTP (postfix)
Mon serveur accepte quelques commandes (LIST, GET...)


C'est aussi un serveur SMTP ? Ou quoi ?

Exemple avec un thread par "tâche" donc 2 threads un pour les
mails, un pour discuter avec le client :


Je ne suis pas sûr de comprendre cette distinction. Qu'est-ce
que tu entends par « discuter », et qu'est-ce que tu entends par
« client » ?

D'habitude, avec un serveur SMTP, les « clients » serait
l'ensemble des connexions actives. Selon le trafic attendu, on
fait un seul thread, qui fait accept, et discute avec les
clients, ou on fait un thread pour l'accept, et un thread (voire
même un processus à part) pour gérer la connexion, une fois
qu'elle est établie. (Est-ce que c'est le dialogue du protocol
que tu entends par « discuter » ?)

Dans le sens d'un gestionnaire de liste, on a aussi une deuxième
signification de client : celui qui est membre de la liste.

quand le client envoi LIST :

- le serveur parcours la liste des client et voit qu'un
client a qqchose à dire, il reconnait la commande, se
connecte a la BDD, recupere la liste, prepare le mail et
l'ajoute a la liste des mails à envoyer du thread mail,
puis on reponds au client : "mail envoyé"


Que signififie cette commande ? Je ne le trouve pas dans RFC
2821.

- la thread mail prend la liste des mails à envoyer et les
envois (en se connectant à postfix).

voilà pour le fonctionnnement du serveur

Cela change t'il qqchose?


Peut-être, si je comprenais quelque chose de ce que devait faire
ton serveur. Ou peut-être pas, tout dépend.

Si chaque connexion de client ne dure pas trop longtemps, ça me
semble acceptable -- si j'ai bien compris, tu ne traites qu'une
connexion à la fois. Si une connexion peut durer plus, il faut
penser à pouvoir gerer plusieurs connexions à la fois.

En tout cas, ce qui envoie les mail doit être un processus ou un
thread à part -- tu ne sais pas combien de temps ta connexion
SMTP va durer.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Flowent
"kanze" a écrit dans le message de news:


C'est aussi un serveur SMTP ? Ou quoi ?


non c'est un simple serveur qui accepte des commandes comme DATE, LIST..
(enfin des commandes que j'ai definit)

Je ne suis pas sûr de comprendre cette distinction. Qu'est-ce
que tu entends par « discuter », et qu'est-ce que tu entends par
« client » ?


Un client etant une personne qui se connecte a mon serveur.
Discuter dans le sens, le client envoi une commande, le serveur repond...

Que signififie cette commande ? Je ne le trouve pas dans RFC
2821.


Ce n'est pas une commande au serveur SMTP mais à mon serveur, il faut bien
voir :
J'ai 2 serveurs : 1 c'est postfix, le 2eme c'est le mien,
En fait mon serveur, recoit une commande (par exemple LIST, cette commande a
ete definit par moi...aucune RFC), mon serveur reconnait LIST et se connecte
a la base de donnee pour aller chercher la liste, puis l'envoi par mail en
se connectant a postfix


Dans mon serveur j'ai donc une liste de sockets (qui sont les clients), je
fais un select sur cette liste pour voir si il y en a1 qui a quelque chose a
dire (par exemple qui envoi LIST), si oui, j'execute la commande et je
reviens sur mon select, attendre..


Voilà je ne sais pas si c'est plus clair!

Avatar
James Kanze
Flowent wrote:
"kanze" a écrit dans le message de news:



C'est aussi un serveur SMTP ? Ou quoi ?



non c'est un simple serveur qui accepte des commandes comme DATE,
LIST.. (enfin des commandes que j'ai definit)


Tu as donc défini ton propre protocol.

Je ne suis pas sûr de comprendre cette distinction. Qu'est-ce
que tu entends par « discuter », et qu'est-ce que tu entends par
« client » ?



Un client etant une personne qui se connecte a mon serveur. Discuter
dans le sens, le client envoi une commande, le serveur repond...


OK.

À la fin, ce qui compte, c'est la durée des connexions. S'il dépasse un
seul aller-retour, ou si le client peut rester connecté pendant que tu
ou lui fait d'autres choses, je pencherais pour une solution avec un
thread ou un processus par connexion.

Que signififie cette commande ? Je ne le trouve pas dans RFC
2821.



Ce n'est pas une commande au serveur SMTP mais à mon serveur, il faut
bien voir :


J'ai 2 serveurs : 1 c'est postfix, le 2eme c'est le mien,


En fait mon serveur, recoit une commande (par exemple LIST, cette
commande a ete definit par moi...aucune RFC), mon serveur reconnait
LIST et se connecte a la base de donnee pour aller chercher la liste,
puis l'envoi par mail en se connectant a postfix


Alors, en réponse à la commande, ton serveur se connecte ailleurs...

Décidemment, il vaut mieux un thread ou un processus par connexion ; tu
ne veux pas tout bloqué parce qu'il y a un problème dans l'autre
connexion.

(On peut, évidemment, faire avec une boucle d'évenemment, et un automat
de gestion de chaque client. Mais c'est en général beaucoup plus
compliqué -- il faut que tu t'occupes explicitement de l'état qui dans
la solution threadée se trouve implicitement dans la pile du thread.)

Dans mon serveur j'ai donc une liste de sockets (qui sont les
clients), je fais un select sur cette liste pour voir si il y en a1
qui a quelque chose a dire (par exemple qui envoi LIST), si oui,
j'execute la commande et je reviens sur mon select, attendre..


Voilà je ne sais pas si c'est plus clair!


Nettement. Mais je crois que dans l'ensemble, un thread (voire même un
processus) par connexion serait plus simple.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


1 2