SIMPLE SERVEUR ECHO (TCP) MULTITHREAD MULTIPLATFORME (WINDOWS / *NIX)

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019 - 2 mars 2007 à 12:54
cs_fabricius Messages postés 4 Date d'inscription jeudi 31 juillet 2008 Statut Membre Dernière intervention 10 novembre 2009 - 10 nov. 2009 à 15:21
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/41702-simple-serveur-echo-tcp-multithread-multiplatforme-windows-nix

cs_fabricius Messages postés 4 Date d'inscription jeudi 31 juillet 2008 Statut Membre Dernière intervention 10 novembre 2009
10 nov. 2009 à 15:21
merci, bien pratique ton serveur pour tester une appli externe.
cs_klapaudius Messages postés 7 Date d'inscription jeudi 9 octobre 2003 Statut Membre Dernière intervention 3 octobre 2009
3 oct. 2009 à 00:50
Pas beaucoup de commentaire dans ce source pas facile pour les débutant en serveur TCP
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
22 déc. 2007 à 23:29
Pour info, la commande pour compiler :

gcc main.c memory.c -lpthread
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
22 déc. 2007 à 23:27
Bon maintenant que j'ai pu installer durablement linux sur ma machine, j'ai pu regarder a vos "problèmes". Pour ceux que ca interesse encore, il suffisais de modifier le début du code dans main.c :

...
#include <string.h>

...

#ifdef WIN32

...

#else

...
#define SOCKADDR_IN struct sockaddr_in
#define SOCKADDR struct sockaddr
#define INVALID_SOCKET -1

...

#endif

C'était vraiment très compliqué... Suffisait de lire la doc...
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
23 avril 2007 à 20:45
m'enerve ca... Pourtant il doit pas manquer grand chose.
amin127 Messages postés 6 Date d'inscription samedi 6 janvier 2007 Statut Membre Dernière intervention 23 avril 2007
23 avril 2007 à 15:17
navré mais comme tu peux le voir cela ne change rien du tout.

:>gcc -o main main.c
main.c:31: error: expected specifier-qualifier-list before ?socketaddr_in?
main.c: In function ?clientManager?:
main.c:65: error: ?socket_t? has no member named ?clientThread?
main.c:70: error: ?socket_t? has no member named ?data?
main.c:73: warning: incompatible implicit declaration of built-in function ?strlen?
main.c: In function ?main?:
main.c:122: error: ?socketaddr_in? undeclared (first use in this function)
main.c:122: error: (Each undeclared identifier is reported only once
main.c:122: error: for each function it appears in.)
main.c:135: error: ?socket_t? has no member named ?data?
main.c:136: error: ?socket_t? has no member named ?data?
main.c:137: error: ?socket_t? has no member named ?data?
main.c:139: error: ?sockaddr? undeclared (first use in this function)
main.c:139: error: expected expression before ?)? token
main.c:139: error: too few arguments to function ?bind?
main.c:146: error: expected expression before ?)? token
main.c:146: error: too few arguments to function ?accept?
main.c:146: error: ?INVALID_SOCKET? undeclared (first use in this function)
main.c:149: error: ?socket_t? has no member named ?clientThread?
main.c:149: warning: passing argument 3 of ?pthread_create? from incompatible pointer type

Au plaisir
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
22 avril 2007 à 21:01
Hum. Et moi qui penssait que ce serait facilement portable :/.
Après un peut de recherche je pense qu'il faut que les linuxiens rajoutent ce code dans la partie #else / #endif du début du code :

/* définit dans sys/socket.h si ma mémoire est bonne : */
#define SOCKADDR_IN socketaddr_in
#define SOCKADDR sockaddr

Explication :
Sous win je crois qu'il y a des macros qui les redéfinissent en majuscules.
En tout cas, j'ai regardé un document sur POSIX, et ses structures sont déclarées en
minuscules. Essais avec ces définitions la donc (a rajouter).

Toutes les autres erreurs doivent venir de ce probleme de type inconnu (le bin veut parler du clientStruct.data qui est de type inconnu par exemple), etc...
dijouxthomas Messages postés 1 Date d'inscription vendredi 30 décembre 2005 Statut Membre Dernière intervention 22 avril 2007
22 avril 2007 à 12:32
Bonjour,
moi aussi j'ai le même problème à la compilation sous linux et changer "socket_t" par "client_sock_struct" ne résout pas le problème.

main.c:29: error: expected specifier-qualifier-list before ?SOCKADDR_IN?
main.c: In function ?clientManager?:
main.c:63: error: ?client_sock_struct? has no member named ?clientThread?
main.c:68: error: ?client_sock_struct? has no member named ?data?
main.c: In function ?main?:
main.c:120: error: ?SOCKADDR_IN? undeclared (first use in this function)
main.c:120: error: (Each undeclared identifier is reported only once
main.c:120: error: for each function it appears in.)
main.c:133: error: ?client_sock_struct? has no member named ?data?
main.c:134: error: ?client_sock_struct? has no member named ?data?
main.c:135: error: ?client_sock_struct? has no member named ?data?
main.c:137: error: ?SOCKADDR? undeclared (first use in this function)
main.c:137: error: expected expression before ?)? token
main.c:137: error: too few arguments to function ?bind?
main.c:144: error: expected expression before ?)? token
main.c:144: error: too few arguments to function ?accept?
main.c:144: error: ?INVALID_SOCKET? undeclared (first use in this function)
main.c:147: error: ?client_sock_struct? has no member named ?clientThread?
main.c:147: warning: passing argument 3 of ?pthread_create? from incompatible pointer type
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
20 avril 2007 à 16:24
Renomme toute les références a "socket_t" et sa déclatation en "client_sock_struct" pour voire.
amin127 Messages postés 6 Date d'inscription samedi 6 janvier 2007 Statut Membre Dernière intervention 23 avril 2007
20 avril 2007 à 12:26
voilà avec : "gcc -o main main.c" c'est ce que j'obtiens:

main.c:29: error: expected specifier-qualifier-list before ?SOCKADDR_IN?
main.c: In function ?clientManager?:
main.c:63: error: ?socket_t? has no member named ?clientThread?
main.c:68: error: ?socket_t? has no member named ?data?
main.c:71: warning: incompatible implicit declaration of built-in function ?strlen?
main.c: In function ?main?:
main.c:120: error: ?SOCKADDR_IN? undeclared (first use in this function)
main.c:120: error: (Each undeclared identifier is reported only once
main.c:120: error: for each function it appears in.)
main.c:133: error: ?socket_t? has no member named ?data?
main.c:134: error: ?socket_t? has no member named ?data?
main.c:135: error: ?socket_t? has no member named ?data?
main.c:137: error: ?SOCKADDR? undeclared (first use in this function)
main.c:137: error: expected expression before ?)? token
main.c:137: error: too few arguments to function ?bind?
main.c:144: error: expected expression before ?)? token
main.c:144: error: too few arguments to function ?accept?
main.c:144: error: ?INVALID_SOCKET? undeclared (first use in this function)
main.c:147: error: ?socket_t? has no member named ?clientThread?
main.c:147: warning: passing argument 3 of ?pthread_create? from incompatible pointer type
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
19 avril 2007 à 21:54
J'utilise Visual Studio sous windows. Je ne pense pas que ca vienne des options de compilation mais du code tel que vu sous linux. (j'ai essayé de compiler avec Code::Blocks -> ca marche et mingw est le portage de GCC).
Peux tu m'indiquer la sortie du compilateur stp (si il y a des changements même minimes surtout au niveau des SOCKADDR_IN, SOCKADDR et INVALID_SOCKET).
En fait, je ne comprend pas la première erreur:
main.c:27: error: expected specifier-qualifier-list before ?SOCKADDR_IN?
Celle-ci doit déclencher les 3/4 des autres.
amin127 Messages postés 6 Date d'inscription samedi 6 janvier 2007 Statut Membre Dernière intervention 23 avril 2007
19 avril 2007 à 12:15
Bonjour,
tjrs des erreurs concernant la compilation sous linux. est ce que tu peux me dire quelles sont les options de compilations que tu utilises.
Merci
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
17 avril 2007 à 21:58
Essai stp de templacer la section #else #endif du début (ou je définit les entêtes) par :

#else
#include <netdb.h>
#include
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SOCKET int
#endif

Tient moi au courant, ca devrais fonctionner maintenant.

Bonne soirée
amin127 Messages postés 6 Date d'inscription samedi 6 janvier 2007 Statut Membre Dernière intervention 23 avril 2007
16 avril 2007 à 12:11
bonjour, je tente de le compiler sous linux et voici ce que j'ai comme erreur :
main.c:27: error: expected specifier-qualifier-list before ?SOCKADDR_IN?
main.c: In function ?clientManager?:
main.c:61: error: ?socket_t? has no member named ?clientThread?
main.c:66: error: ?socket_t? has no member named ?data?
main.c:69: warning: incompatible implicit declaration of built-in function ?strlen?
main.c: In function ?main?:
main.c:118: error: ?SOCKADDR_IN? undeclared (first use in this function)
main.c:118: error: (Each undeclared identifier is reported only once
main.c:118: error: for each function it appears in.)
main.c:131: error: ?socket_t? has no member named ?data?
main.c:132: error: ?socket_t? has no member named ?data?
main.c:133: error: ?socket_t? has no member named ?data?
main.c:135: error: ?SOCKADDR? undeclared (first use in this function)
main.c:135: error: expected expression before ?)? token
main.c:135: error: too few arguments to function ?bind?
main.c:142: error: expected expression before ?)? token
main.c:142: error: too few arguments to function ?accept?
main.c:142: error: ?INVALID_SOCKET? undeclared (first use in this function)
main.c:145: error: ?socket_t? has no member named ?clientThread?
main.c:145: warning: passing argument 3 of ?pthread_create? from incompatible pointer type

bien à toi
bonne journée
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 21:19
Voila la nouvelle version. Le serveur crashait a cause d'un -1 retourné par un recv(). J'ai aussi rajouté deux commandes clients : QUIT et VERSION.

PS : désolé pour le triple post enchainé... je ne suis pas très organisé xD.
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 21:05
Bon j'ai trouvé la ou ça crash quand le client est killé. Sinon j'ai tout refais en pthread, j'up bientôt la nouvelle version.
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 19:52
Merci pour ton commentaire. J'ai donc encore ce problème de thread :p. Je me repenche sur mon code ^^.
cs_max12 Messages postés 1491 Date d'inscription dimanche 19 novembre 2000 Statut Modérateur Dernière intervention 7 juillet 2014
2 mars 2007 à 19:50
Je te conseil d'utiliser uniquement PThread tant qu'a faire du multiplateforme, dans le pire des cas tu vas simplement inclure un DLL avec la version Windows, et lorsque tu voudras faire la synchronisation ce sera plus simple (et sans synchro c'est le crash).

Ensuite il y a le bug du closehandle dans ton code qui a été mensionné, il faut le faire lorsque tu en as terminé avec le thread c'est tout, dans mon cas je le faisait a la fin de la fonction du thread, mais je ne sais pas si c'est politiquement correct même si aucun problème ne survenais. Le read retourne -1 aussi parfois. Tu ne vérifie pas non plus tes memory alloc alors en cas de out of memory ton prog crash.

et finalement je suis rouillé un peu avec pthread mais il y a une commande a mettre a la fin de ta fonction client_manager quelque chose du genre p_thread_exit ou je suis pas certain (sous Nux c'était segmentation fault sinon :S)

bon c'est pas mal ce que j'avais a dire

http://www.cppfrance.com/codes/SERVEUR-MULTITHREAD-SOUS-LINUX-WINDOWS-MYSQL-VCPLUSPLUS-DEVCPLUSPLUS_40044.aspx
C'est de moi et je crois avoir été assez accomodant sur la compilation facile :P

A+
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 17:22
Merci ;).
Par contre j'ai remarqué un problème :/. Quand un client telnet est killé (test fais avec telnet), le serveur plante. Est ce que quelqu'un aurait une idée?
ncoder Messages postés 244 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 6 avril 2008 1
2 mars 2007 à 17:20
Je connaissais l'utilité de WaitForMultipleObjects()

OK merci pour l'explication de CloseHandle().
Je mélangeais le handle et le thread, en gros.

A+ et bien pour ta source, on comprend facilement ce que tu fais.
Bonne continuation
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 17:13
C'est WaitForMultipleObjects() qui attend que les threads soient terminés. Mais je ne l'utilise pas.
Le CloseHandle() sert juste a libérer l'handle. l'handle est indépendant du thread. C'est juste une sorte d'ID. En gros le CloseHandle() sert juste à dire a windows qu'il peut utiliser l'handle pour autre chose ; comme le thread se gère tout seul (il n'est pas contrôlé ailleurs dans le code) on en a plus besoin.
ncoder Messages postés 244 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 6 avril 2008 1
2 mars 2007 à 17:06
Merci pour tes réponses.

Quand le thread se termine tout seul, je pense qu'il faut quand meme faire CloseHandle().

En effet, TerminateThread() m'a l'air louche. On peut peut-etre risquer moins en faisant TerminateThread() suivi de CloseHandle()... (l'un termine le thread l'autre le ferme?)

Ce que tu me dis, c'est que comme CloseHandle() ne termine pas le thread mais juste "attend", dès que le thread se termine de lui-meme, CloseHandle() s'occupe du reste. Et ainsi tout fonctionne, et c'est pas génant que CreateThread soit immédiatement suivi de CloseHandle(), puisque celui-ci n'interrompt pas le thread durant son lancement.

Est-ce exact ?
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 16:54
Pour le CloseHandle() sur les thread, on peut lire dans msdn :

"Closing a thread handle does not terminate the associated thread. To remove a thread object, you must terminate the thread, then close all handles to the thread."
(http://msdn2.microsoft.com/en-us/library/ms724211.aspx)

Comme le thread se termine tout seul (quand le client quite...), il n'y a pas besoin de le terminer... si?

Quand a TerminateThread(), msdn nous dit que c'est une fonction dangereuse (cf. http://msdn2.microsoft.com/en-us/library/ms686717.aspx). Je pense qu'elle devrait être utilisée uniquement pour le debug d'ailleurs car trop louche à utiliser :D.

Et le WaitForMultipleObjects() sert à attendre que tous les threads soient terminés.

Je devrais théoriquement libérer l'handle du thread après l'avoir terminé, mais comme ces threads se terminent tout seuls après la fermeture des clients ça devrait être bon, non? En tout cas les essais montres que ça fonctionne :p. Essai donc le serveur avec plusieurs client telnet sur le port 1234.
ncoder Messages postés 244 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 6 avril 2008 1
2 mars 2007 à 15:55
Deuxième chose :
Pourquoi tu enchaines "CloseHandle()" immédiatement après avoir fait "CreateThread()" ?

Il faudrait attendre que les threads se soient terminés tous seuls avant de faire "CloseHandle()", non ?
Sinon ils sont arrétés immédiatement après leur lancement, non ?

Dans msdn ils utilisent WaitForMultipleObjects(MAX_THREADS, hThread, TRUE, INFINITE);, et ensuite CloseHandle().
Cf : http://msdn2.microsoft.com/en-us/library/ms682516.aspx

Là je ne comprends pas tout ...
ncoder Messages postés 244 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 6 avril 2008 1
2 mars 2007 à 15:37
Bonjour,

CloseHandle() laisse le thread "tranquille" ??

Pour forcer un thread à se terminer, dois-je donc obligatoirement utiliser TerminateThread() (et non CloseHandle() ) ?

Je crois avoir lu un jour de n'utiliser que rarement TerminateThread() (en cas d'urgence), c'est vrai ?

Quelle est la différence entre TerminateThread() et CloseHandle() ?

Merci de vos réponses
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 14:05
J'ai cru comprendre sur msdn qu'un CloseHandle() ne terminait pas le thread tout de suite mais le laissait juste "tranquille". J'en conclu donc que c'est à peu prêt équivalent a pthread_detach(). J'ai donc simplifié un peu le code en faisant comme avec les pthreads.
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 13:08
Voila. J'ai rajouté un CloseHandle() à la fin du thread.
Cphil51 Messages postés 87 Date d'inscription jeudi 22 juin 2006 Statut Membre Dernière intervention 24 septembre 2007
2 mars 2007 à 12:59
Je regarde a ca tout de suite.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
2 mars 2007 à 12:54
Te manque une série de #ifdef, CreateThread retourne un handle qu'il convient de fermer par CloseHandle() sinon ta table de handles risque fort de saturer.
Rejoignez-nous