Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1028 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Sockets asynchrones en C sous Windows

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Sockets asynchrones en C sous Windows

n°1864866
tomap
Posté le 23-03-2009 à 16:46:53  profilanswer
 

Salut, est ce que quelqu'un sais où je pourrais trouver de la doc concernant l'utilisation des sockets asynchrones en langage C ? C'est beaucoup différents par rapport au sockets synchrones classiques ?
Merci.

mood
Publicité
Posté le 23-03-2009 à 16:46:53  profilanswer
 

n°1865012
xilebo
noone
Posté le 23-03-2009 à 22:15:02  profilanswer
 

Une socket n'est ni synchrone ni asynchrone, c'est l'utilisation que tu en fais qui va l'être ou non.
 
Pour une utilisation asynchrone (c'est à dire que tu ne sais pas quand tu reçois des données), pour éviter de l'attente active ou du polling sur la réception, l'idéal est d'utiliser la fonction select qui te permettra de détecter que des données sont reçues pour pouvoir les lire.
 
Généralement, j'ai un thread pour l'envoi, et un thread pour la réception, mais ce n'est pas obligatoire.
 
 
Ici une documentation qui explique bien comment utiliser ces fonctions : http://mapage.noos.fr/emdel/reseaux.htm
 

n°1865068
tomap
Posté le 24-03-2009 à 02:40:45  profilanswer
 

Salut xilebo, merci pour la repense. J'ai déjà vu ce lien (qui est bien, au passage), l'utilisation de sockets que je veux faire c'est en fait pour faire un serveur qui peut supporté la connexion de plusieurs client, donc si je fait comme expliqué sur ce lien en faisant en sorte de créer un thread pour chaque client connecté, ça ne va pas le faire (beaucoup trop de threads) d'où mon envi d'une utilisation asynchone pour éviter les threads.
Je peut donc faire tout ça grâce à select() ? (c'est seulement ça qui caractérise les sockets asynchrones) ?

n°1865404
Pat333
Posté le 24-03-2009 à 16:38:44  profilanswer
 

xilebo a écrit :

Une socket n\'est ni synchrone ni asynchrone, c\'est l\'utilisation que tu en fais qui va l\'être ou non.


 
N\'importe quoi.
C\'est expliqué en long et en large dans MSDN  (avec des exemples de \"asynchronous sockets\" !)

n°1865427
xilebo
noone
Posté le 24-03-2009 à 17:31:15  profilanswer
 

Pat333 a écrit :


 
N\'importe quoi.
C\'est expliqué en long et en large dans MSDN  (avec des exemples de \"asynchronous sockets\" !)


 
Ton message ne sert à rien, comme tes 3 seuls autres messages sur ce forum.
 
Si tu n'es pas d'accord, la moindre des choses, c'est d'expliquer pourquoi, et pas citer une phrase passe partout comme tu viens de le faire.
 
Je persiste : une socket n'est ni synchrone, ni asynchrone, c'est l'utilisation que tu vas en faire qui va l'être. Je précise : généralement, une utilisation synchrone d'une socket requiert une configuration en mode bloquant (mais pas forcément), alors qu'une utilisation asynchrone requiert une socket configurée en mode non bloquant (mais pas forcément non plus).
 
En mode bloquant, ton recv ne retournera pas tant que tu n'auras pas recu de données ou une erreur, en mode non bloquant, ta fonction recv retourne toujours, données recues ou pas. C'est pour cela qu'il faut utiliser la fonction select pour eviter l'attente active ou le polling.
 
Le mode asynchrone suppose que tu n'as aucune synchronisation entre les données émises (send) et les données recues (recv). Généralement, on a un thread séparé pour chacune des tâches mais ce n'est pas obligatoire.
 

n°1865449
tomap
Posté le 24-03-2009 à 18:28:06  profilanswer
 

Pour un serveur qui permet de faire communiquer plusieurs clients (un chat instantané), vous me conseillez une utilisation synchrone (en mode bloquant) ou bien une utilisation asynchrone ?

 

J'ai commencé à réaliser ça en mode synchrone en utilisant les threads au niveau du serveur (je crée un thread pour chaque client connecté), mais je trouve que comme ça il y aura beaucoup trop de threads lancé simultanément au niveau du serveur, et aussi y aura le problème de communication entre threads (quand on veux par exemple qu'un client envoi au autres clients connectés).
Pour réglé un peut ses problèmes, on m'a dirigé vers select() donc: sockets non bloquants + threads + select().

 

Mais je me demande si avec tout ça, ça ne sera pas plus facile d'utiliser des sockets en mode non bloquant (asynchrone); Il parais qu'une utilisation asynchrone est plus difficile qu'une utilisation synchrone + threads.

 

Vous en dite quoi ?

 

En fait quand j'ai voulu utiliser les sockets en mode non bloquant j'ai suivi le schéma de serveur-multi-clients montré sur ce lien http://mapage.noos.fr/emdel/reseaux.htm , mais comment faire ensuite pour diminuer de nombre de threads grâce select() ? Parce qu'un thread par client connecté, c'est beaucoup..
Dois-je créer un thread par client connecté, et dans chaque thread y aura la fonction select() qui va suspendre ce thread quand il n y a pas de donnée à recevoir ... ?


Message édité par tomap le 24-03-2009 à 18:42:22
n°1865458
xilebo
noone
Posté le 24-03-2009 à 18:51:11  profilanswer
 

La fonction select accepte en paramètre des ensembles de descripteur de fichiers ( sockets par exemple). Tu peux gérer toutes tes connexions dans un seul thread de réception, en appelant la fonction select avec l'ensemble de tes sockets. la fonction select retournera que des données sont recues sur au moins une connexion (si tu dois recevoir des données), après il te suffira de tester sur quelle connexion sont recues les données pour effectuer ton traitement.
 
man select sur google.fr
 
ou à nouveau le lien que je t'ai donné ci-dessus :http://mapage.noos.fr/emdel/reseaux.htm#select  
 

n°1865466
tomap
Posté le 24-03-2009 à 19:32:55  profilanswer
 

xilebo a écrit :

La fonction select accepte en paramètre des ensembles de descripteur de fichiers ( sockets par exemple). Tu peux gérer toutes tes connexions dans un seul thread de réception, en appelant la fonction select avec l'ensemble de tes sockets. la fonction select retournera que des données sont recues sur au moins une connexion (si tu dois recevoir des données), après il te suffira de tester sur quelle connexion sont recues les données pour effectuer ton traitement.

 

man select sur google.fr

 



Mais le problème c'est que je ne peut pas appelé select() avec l'ensemble de mes sockets puisqu'il ne sont pas connu au début ! C'est la fonction accept() qui retourne le socket client lors de la connexion d'un client. Je ne peut donc pas connaitre à l'avance tout les sockets clients qu'il y aura pour les passer à select(); Et encore moins tester sur quelle connexion sont reçues les données pour effectuer mon traitement; de plus que la fonction accept() est bloquante.
Je ne vois donc pas comment faire pour gérer mes connexions dans un seul thread. A moins que select() retourne une valeur précise quand il y a une demande de connexion.. ce qui n'est pas le cas à ce que je vois.

 

Le schéma actuel (sans select) est le suivant:

Début Boucle:
  attendre une connexion: accept()  // ça me retourne le socket client qui me permettra de communiquer.
  créer un thread avec le socket client
Fin Boucle.

à quel niveau j'aurai à utiliser select() pour n'avoir qu'un seul thread à gérer ?

 


Message édité par tomap le 24-03-2009 à 19:45:37
n°1865481
xilebo
noone
Posté le 24-03-2009 à 20:03:49  profilanswer
 

je n'ai pas dit un seul thread, j'ai juste dit un thread pour les réceptions.
 
Tu peux avoir un thread pour l'envoi, un thread pour la réception (ou bien un thread pour les 2), et un thread d'écoute pour accepter les connexions. Tu n'as qu'à stocker tes sockets dans une liste commune aux 2 threads, mais attention aux accès concurrentiels (mutex pour protéger les écritures).
 
Ex (j'ai pas vérifié l'intégrité) :  
 
Thread d'écoute :
 
Debut boucle
 Attendre Accept
 Si connexion acceptée
   Lock  
    ajouter connexion dans liste
   Unlock
Fin boucle.
 
 
Thread d'envoi et reception
 
Debut boucle
 Lock
  ajouter liste de descripteur dans structure prevue a cet effet (FDSET)
 Unlock
 select sur ta liste
 si données recues
 traiter...
 fin si
Fin Boucle

n°1865890
tomap
Posté le 25-03-2009 à 19:28:08  profilanswer
 

Ok. Est ce que le mieux serai que la liste contenant les sockets client (valeurs int) soit une liste chainée, ou un tableau d'entier, ou ... ?
Sachant que je dois tester si des données ont été reçu sur la liste des sockets, on la parcourant; et qu'il faut retiré la valeur correspondante au socket client correspondant au client qui se déconnecte (qui envoi un message pour dire qu'il veux se déconnecter ou quand recv() renvoi une valeur =<0 avec ce socket client).

Message cité 1 fois
Message édité par tomap le 25-03-2009 à 19:41:54
mood
Publicité
Posté le 25-03-2009 à 19:28:08  profilanswer
 

n°1865967
Emmanuel D​elahaye
C is a sharp tool
Posté le 26-03-2009 à 09:12:54  profilanswer
 

tomap a écrit :

Ok. Est ce que le mieux serai que la liste contenant les sockets client (valeurs int) soit une liste chainée, ou un tableau d'entier, ou ... ?
Sachant que je dois tester si des données ont été reçu sur la liste des sockets, on la parcourant; et qu'il faut retiré la valeur correspondante au socket client correspondant au client qui se déconnecte (qui envoi un message pour dire qu'il veux se déconnecter ou quand recv() renvoi une valeur =<0 avec ce socket client).


Oui, c'est une technique courante.
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
n°1866396
xilebo
noone
Posté le 26-03-2009 à 20:11:36  profilanswer
 

n'oublie pas de protéger l'insertion et la suppression d'une socket dans la liste par des mutex.  
 
Et dans tous les cas, il faut toujours tester la valeur de retour d'un appel système. Attention, sous linux (windows je sais pas), recv peut renvoyer -1 sans avoir de socket fermée, il faut egalement tester errno, car tu peux avoir été interrompu par un signal (errno == EINTR).

n°1866398
tomap
Posté le 26-03-2009 à 20:26:05  profilanswer
 

J'ai une liste shared_list pour contenir les sockets clients connectés.
Dans le thread principale main() j'ai une boucle qui attend les connexion et les ajoute dans la liste. Et j'ai un thread dans lequel j'ai utilisé select() pour attendre de recevoir des données. Mais quand je lance le serveur (sans lancé aucun client au début) select() me retourne -1, et ça m'affiche donc "error" en boucle.
Comment faire donc ? au début c'est normale qu'il n y ai aucun socket client dans la liste.

Code :
  1. struct shared
  2. {
  3.    struct elem *tete;
  4.    pthread_mutex_t mutex;
  5. }shared_list;
  6. static void *task_client (void *p_data)
  7. {
  8.    struct elem *p;
  9.    while (1)
  10.    {
  11.          // display(shared_list.tete);
  12.          fd_set readfs;
  13.          FD_ZERO (&readfs);
  14.          pthread_mutex_lock (&shared_list.mutex);
  15.          p = shared_list.tete;
  16.          while( p != NULL )
  17.          {
  18.             FD_SET (p->x, &readfs);
  19.             p = p->next;
  20.          }
  21.          pthread_mutex_unlock (&shared_list.mutex);
  22.          int err = select (FD_SETSIZE, &readfs, NULL, NULL, NULL);
  23.          switch (err)
  24.          {
  25.          case 0: /* timeout */ break;
  26.          case -1: /* error */ printf ("error: %d\n", WSAGetLastError()); break;
  27.          default:
  28.             p = shared_list.tete;
  29.             while( p != NULL )
  30.             {
  31.                if (FD_ISSET (p->x, &readfs))
  32.                {
  33.                   char data[128];
  34.                   int n = recv (p->x, data, sizeof data - 1, 0);
  35.                   if (n > 0)
  36.                   {
  37.                      data[n] = '\0';
  38.                      printf("Client %d a envoye: %s\n", p->x, data);
  39.                      if( strcmp(data, "cmd1" ) == 0 )
  40.                         send(p->x, "voici le service 1", strlen("voici le service 1" ), 0);
  41.                      else if( strcmp(data, "cmd2" ) == 0 )
  42.                         send(p->x, "voici le service 2", strlen("voici le service 2" ), 0);
  43.                      else
  44.                         send(p->x, "voici le service etc...", strlen("voici le service etc..." ), 0);
  45.                   }
  46.                   else
  47.                   {
  48.                      pthread_mutex_lock (&shared_list.mutex);
  49.                      shared_list.tete = delete_elem(shared_list.tete, p->x);
  50.                      pthread_mutex_unlock (&shared_list.mutex);
  51.                   }
  52.                }
  53.                p = p->next;
  54.             }
  55.          } // fin switch
  56.    }
  57.    return NULL;
  58. }
  59. int main ()
  60. {
  61.    /* etc ... du code ici ... */
  62.    shared_list.tete = NULL;
  63.    shared_list.mutex = PTHREAD_MUTEX_INITIALIZER;
  64.    pthread_t thread;
  65.    pthread_create (&thread, NULL, task_client, NULL);
  66.    do
  67.    {
  68.       csock = accept (sock, (SOCKADDR*) &csin, &csinsize);
  69.       pthread_mutex_lock (&shared_list.mutex);
  70.       shared_list.tete = ajouter_elememt (shared_list.tete, csock);
  71.       pthread_mutex_unlock (&shared_list.mutex);
  72.    }
  73.    while(1);
  74.    /* etc ... le reste du code ... */
  75. }


Message édité par tomap le 26-03-2009 à 22:36:12
n°1866403
xilebo
noone
Posté le 26-03-2009 à 20:35:46  profilanswer
 

Sous windows, il faut initialiser la pile reseau en appelant WSAStartup() et WSACleanUup()
 
 
Utilisation : http://msdn.microsoft.com/en-us/li [...] S.85).aspx
 

n°1866405
tomap
Posté le 26-03-2009 à 20:50:22  profilanswer
 

.


Message édité par tomap le 26-03-2009 à 20:56:21
n°1866410
tomap
Posté le 26-03-2009 à 20:57:55  profilanswer
 

En fait j'utilise déjà WSAStartup() et WSACleanup() mais il y a quand même le problème que j'ai cité plus haut avec select() (elle me retoun -1)


Message édité par tomap le 26-03-2009 à 22:23:24
n°1866417
xilebo
noone
Posté le 26-03-2009 à 21:17:47  profilanswer
 

Dans ce cas, teste l'erreur avec WSAGetLastError() http://msdn.microsoft.com/en-us/li [...] S.85).aspx
 
 

n°1866428
tomap
Posté le 26-03-2009 à 21:53:08  profilanswer
 

WSAGetLastError() me retourne la valeur 10022

 
Citation :

WSAEINVAL 10022 : Invalid argument.
Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening.

 

ça dois être parce que j'appelle FD_SET() avec le 1er argument qui est naturellement invalide vu que la liste est initialement vide (tete = NULL).

 

Donc pour régler ça, dans ma boucle je teste si shared_list.tete != NULL, mais bon, ça va bouffer du CPU en bouclant quand il n y a aucun client connecté (liste vide càd tete=NULL) ...

Code :
  1. while(1)
  2. {
  3.    if(shared_list.tete != NULL)
  4.    {
  5.        /*tout le reste*/
  6.    }
  7. }
 

Une autre question: est ce qu'il faut à chaque fois que je veux "lire" une valeur de la liste que j'utilise un mutex (lock/unlock) ? Ou alors ce n'est naicessaire que lors de l'écriture sur la liste (lors d'ajout/suppression...) ?

 

EDIT:
Tient je remarque un truc bizarre. Je lance le serveur, puis je lance deux clients (client_1 puis client_2); lorsque client_1 envoi un message au serveur il reçoit la repense (normale), mais après lorsque client_2 envoi un message il ne reçoit pas la repense (il reste bloqué sur recv), mais il suffit que client_1 envoi un autre message au serveur pour que client_2 reçoit la repense à son 1er message ! Je ne vois pas vraiment où est le problème (cf le code plus haut).

 

Message cité 1 fois
Message édité par tomap le 26-03-2009 à 22:43:48
n°1866709
tpierron
Posté le 27-03-2009 à 14:32:10  profilanswer
 

tomap a écrit :

EDIT:
Tient je remarque un truc bizarre. Je lance le serveur, puis je lance deux clients (client_1 puis client_2); lorsque client_1 envoi un message au serveur il reçoit la repense (normale), mais après lorsque client_2 envoi un message il ne reçoit pas la repense (il reste bloqué sur recv), mais il suffit que client_1 envoi un autre message au serveur pour que client_2 reçoit la repense à son 1er message ! Je ne vois pas vraiment où est le problème (cf le code plus haut).


 
Normal. Quand le thread principal dans main() recoit une connexion, il va l'ajouter dans la liste. Cool, sauf que le thread d'écoute, s'il est bloqué dans l'appel select() (donc plus d'une connexion), la liste des descripteurs sur lesquels la fonction écoute n'incluera evidemment pas la nouvelle connexion. Connexion qui sera incluse seulement lors de la réception du message suivant.
 
Bref:

  • Va falloir notifier ton thread d'écoute en envoyant un message de service sur une des sockets
  • Quand la liste est vide, tu dois certainement faire une boucle active, vu que ton select renvoie sans cesse -1. Peut-être un sémaphore serait utile dans ce cas.

n°1866723
tomap
Posté le 27-03-2009 à 14:58:03  profilanswer
 

En fait avec cette méthode il y a un problème de conception.
 
J'ai un thread d'écoute (main) qui attend et accept les connexions (sockets clients) et les ajoute dans une liste. Ok.
 
Et j'ai le thread (task_client) qui ajoute les sockets de la liste dans FD_SET puis se bloque sur select(), à chaque tour de boucle. Ok, mais y a un problème:
quand un client_1 se connecte, il est ajouté à la liste, puis il est ajouté à FD_SET() et le thread task_client se bloque sur select() en attendant de recevoir des données des clients qui sont ajoutés avec FD_SET (pour l'instant y a que client_1), quand un autre client_2 se connecte il est ajouté dans la liste mais il n'est pas encore ajouté à FD_SET() puisque le thread task_client est bloqué sur select() en attendant des données de client_1. Donc client_2 sera ajouté à FD_SET() au prochain tour de boucle, c'est a dire seulement quand select() se débloque en recevant des données de client_1, d'où le problème bizarre que j'ai cité dans le poste si-dessus.
 
Je ne vois donc toujours pas comment faire. Est ce que select() peut nous informer qu'il y a une connexion d'un client qui arrive, pour pouvoir utilisé accept() quand c'est le cas ?

n°1866728
tomap
Posté le 27-03-2009 à 15:06:06  profilanswer
 

tpierron a écrit :


Bref:

  • Va falloir notifier ton thread d'écoute en envoyant un message de service sur une des sockets
  • Quand la liste est vide, tu dois certainement faire une boucle active, vu que ton select renvoie sans cesse -1. Peut-être un sémaphore serait utile dans ce cas.

Sorry, j'ai posté sans voir ton message.
Peux-tu mieux expliquer comment "notifier ton thread d'écoute en envoyant un message de service sur une des sockets", je n'ai pas compris.
Merci

n°1866731
tpierron
Posté le 27-03-2009 à 15:20:13  profilanswer
 

tomap a écrit :

Peux-tu mieux expliquer comment "notifier ton thread d'écoute en envoyant un message de service sur une des sockets", je n'ai pas compris.


Bah, dans ta boucle, tu regardes déjà quelle commande tu recoies. Alors rajoutes une commande bidon pour notifier le thread en écoute que la liste des sockets à changé :
 

Code :
  1. if( strcmp(data, "cmd1" ) == 0 )
  2.     send(p->x, "voici le service 1", strlen("voici le service 1" ), 0);
  3. else if( strcmp(data, "cmd2" ) == 0 )
  4.     send(p->x, "voici le service 2", strlen("voici le service 2" ), 0);
  5. else if (strcmp(data, "OOB" ))
  6.     send(p->x, "voici le service etc...", strlen("voici le service etc..." ), 0);


 
Et dans le main() :

Code :
  1. do
  2. {
  3.     int notify = 0;
  4.     csock = accept (sock, (SOCKADDR*) &csin, &csinsize);
  5.     pthread_mutex_lock (&shared_list.mutex);
  6.     if (shared_list.tete)
  7.         notify = shared_list.tete->x;
  8.     shared_list.tete = ajouter_element (shared_list.tete, csock);
  9.     pthread_mutex_unlock (&shared_list.mutex);
  10.     if (notify)
  11.         send(notify, "OOB", 3, 0);
  12. }
  13. while(1);


 
Pas trop beaucoup testé, mais tu vois l'idée.

n°1866787
tomap
Posté le 27-03-2009 à 17:28:10  profilanswer
 

tpierron a écrit :


Et dans le main() :

Code :
  1. do
  2. {
  3.     int notify = 0;
  4.     csock = accept (sock, (SOCKADDR*) &csin, &csinsize);
  5.     pthread_mutex_lock (&shared_list.mutex);
  6.     if (shared_list.tete)
  7.         notify = shared_list.tete->x;
  8.     shared_list.tete = ajouter_element (shared_list.tete, csock);
  9.     pthread_mutex_unlock (&shared_list.mutex);
  10.     if (notify)
  11.         send(notify, "OOB", 3, 0);
  12. }
  13. while(1);




 
Ben 'notify' sera initialisé avec le 1er socket de la liste, et quand on fait send(notify, "OOB", 3, 0); ça va envoyer "OBB" au client qui s'est connecté avec le socket 'notify' (le 1er client de la liste). ça ne va donc pas envoyer un message au thread pour débloquer select().
 

n°1866806
tpierron
Posté le 27-03-2009 à 18:43:20  profilanswer
 

tomap a écrit :

Ben 'notify' sera initialisé avec le 1er socket de la liste, et quand on fait send(notify, "OOB", 3, 0); ça va envoyer "OBB" au client qui s'est connecté avec le socket 'notify' (le 1er client de la liste). ça ne va donc pas envoyer un message au thread pour débloquer select().


 
 [:talen] Ah ouais, c'est n'importe quoi ce que je t'es raconté. En fait pas tout à fait, et même si c'est limite de la bidouille, le premier client à se connecter sur le serveur, devrait être justement ton thread d'écoute, comme ça tu pourras interrompre l'attente sur le select en passant des messages directement au thread.
 
L'autre solution, c'est d'utiliser un thread par connexion (Apache fonctionne comme ça par exemple).

n°1866814
tomap
Posté le 27-03-2009 à 19:15:54  profilanswer
 

tpierron a écrit :

le premier client à se connecter sur le serveur, devrait être justement ton thread d'écoute


Je n'ai pas bien compris, tu veux dire qu'à chaque connexion d'un client, j'envoie une requête au 1er client pour qu'il me renvoi une repense pour que ça débloque l'attente sur le select() ? C'est trop à l'arrache ça..

 

J'ai eu l'idée suivante: à chaque connexion d'un client j'envoie un message à moi même (127.0.0.1) via un scoket udp qui est permanent dans la tête de la liste (avec sendto()). Donc j'ai fait:

Code :
  1. SOCKADDR_IN localsin;
  2.    SOCKET localsock = socket(AF_INET, SOCK_DGRAM, 0);
  3.    localsin.sin_addr.s_addr = inet_addr("127.0.0.1" );
  4.    localsin.sin_port = htons (SERVER_PORT_LISTENING);
  5.    localsin.sin_family = AF_INET;
  6.    shared_list.tete = add_elem (NULL, localsock);
  7.    do
  8.    {
  9.       csock = accept (sock, (SOCKADDR*) &csin, &csinsize);
  10.       printf("Client connected with socket %d from %s:%d\n",
  11.             csock, inet_ntoa (csin.sin_addr), htons (csin.sin_port));
  12.       pthread_mutex_lock (&shared_list.mutex);
  13.       shared_list.tete = add_elem (shared_list.tete, csock);
  14.       pthread_mutex_unlock (&shared_list.mutex);
  15.       sendto(localsock, "OOB", 3, 0, (SOCKADDR*) &localsin, sizeof localsin);
  16.    }
  17.    while(1);


Malheureusement, ça n'as pas l'aire de marché. select() ne se débloque pas lorsqu'il y a des données à recevoir venant d'un socket udp (envoyés avec sendto) ?

 
tpierron a écrit :

L'autre solution, c'est d'utiliser un thread par connexion (Apache fonctionne comme ça par exemple).


C'est le plus simple, malheureusement l'application serveur que je veux faire dois permettre la connexion de plusieurs clients (un chat instantané) et donc si je fait comme ça il y aura beaucoup trop de threads lancés au niveau du serveur, d'où mon utilisation actuel de select.

Message cité 1 fois
Message édité par tomap le 27-03-2009 à 19:17:50
n°1866831
xilebo
noone
Posté le 27-03-2009 à 20:23:40  profilanswer
 


 

tomap a écrit :


C'est le plus simple, malheureusement l'application serveur que je veux faire dois permettre la connexion de plusieurs clients (un chat instantané) et donc si je fait comme ça il y aura beaucoup trop de threads lancés au niveau du serveur, d'où mon utilisation actuel de select.


 
 
Ca dépend ce que tu appelles "trop de threads". Si c'est 100000, c'est non (avec les architectures standards), mais si c'est 1000 ou moins, ton système le supportera. Mais pour un chat, t'es forcément en dessous, car au dela de 50-100 personnes, ça devient vite le bordel, et 50-100 threads, c'est rien du tout.  

n°1866850
tomap
Posté le 27-03-2009 à 20:58:12  profilanswer
 

Je n'aimerai pas être limité par le nombre de threads et du coup limité le nombres de clients, on ne sais jamais, je veux prévoir ça dés le début.

 

Sinon y a pas un autre moyen pour débloquer select() à partir du thread principale ?


Message édité par tomap le 27-03-2009 à 20:59:05
n°1866852
tpierron
Posté le 27-03-2009 à 21:22:39  profilanswer
 

Rah, mais pourquoi te casses tu la tête avec une socket UDP ?
 
Dans ta fonction task_client, la première chose que tu fais, c'est de te connecter (TCP) à ton serveur qui est bloqué présentement sur accept(). Du genre :
 

Code :
  1. int sock = connect_to_ip("127.0.0.1", port);


  • connect_to_ip est une fonction bidon, à toi de la faire.
  • sock : on s'en fou, la socket pour envoyer des données à déjà été incluse dans ta liste partagée. Cela dit ne ferme pas cette socket tout de suite, fais le lorsque tu es sur le point de quitter le thread.
  • Pour blinder un peu plus le code, faudrait quand meme un mécanisme pour s'assurer que la première connexion provient bien du thread, via un message par exemple.


Normallement avec ça, ton thread principal devrait pouvoir débloquer ton thread d'écoute.
 
Edit: pour rejoindre ce que dit xilebo, fait aussi gaffe avec les FD_SET. Tu ne pourras pas multiplexer des milliers de connexions avec cette méthode de toute façon. Pour info sur Win32, FD_SETSIZE est définit à 64. 64 threads, ça ne représente rien comme charge.

Message cité 1 fois
Message édité par tpierron le 27-03-2009 à 21:26:08
n°1866862
tomap
Posté le 27-03-2009 à 22:23:06  profilanswer
 

Bon ok je vais faire comme ça alors.

tpierron a écrit :

Edit: pour rejoindre ce que dit xilebo, fait aussi gaffe avec les FD_SET. Tu ne pourras pas multiplexer des milliers de connexions avec cette méthode de toute façon. Pour info sur Win32, FD_SETSIZE est définit à 64. 64 threads, ça ne représente rien comme charge.


Oui mais je peux créer par exemple 5 threads comme task_client qui utilisent select() et j'aurai donc géré 64*5 client en ne créant que 5 threads, au lieux de 64*5 threads si je crée un thread par client connecté.

 

Mais bon je pourrais aussi faire me simplifié la vie en créant un thread par client connecté et définir une limite maximal de clients connecté et mettre en place 2 ou 3 serveurs; si le 1er est à la limite du nombre de clients autorisé, on envoi une requête au client qui veux se connecter pour le redirigé au 2eme serveur et ainsi de suite... Je vais y réfléchir.


Message édité par tomap le 27-03-2009 à 23:55:11
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Sockets asynchrones en C sous Windows

 

Sujets relatifs
Fonction C times en Ada.[Débutant] Arret d'une boucle en C++
[AIDE SVP] Lancer projet C++ sur autre un ordinateur sans VS 2008[résolu][C] Strlen - erreur de segmentation
[Visual C#] Problème projet après changement de PCC, execution de sous programme [TERMINE]
Programme C avec interface webTransfert de fichier de windows vers linux
Programmation C - DSP - MATLAB => CCS 
Plus de sujets relatifs à : Sockets asynchrones en C sous Windows


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR