2010-11-13 33 views
0

J'ai un serveur et classes client mais le problème est: quand je fais boucle infinie pour accepter la connexion entrante je ne peux pas recevoir toutes les données reçues du client tout en acceptant les connexions parce accepter les blocs jusqu'à ce que la connexion est acceptée, mon Code:sockets question

for (;;) 
    { 
     boost::thread thread(boost::bind(&Irc::Server::startAccept, &s)); 
     thread.join(); 
     for (ClientsMap::const_iterator it = s.begin(); it != s.end(); ++it) 
     { 
      std::string msg = getData(it->second->recv()); 
      std::clog << "Msg: " << msg << std::endl; 
     } 
    } 
+1

Quel est le point de démarrer un fil et de le rejoindre immédiatement? –

+0

Je pensais que join attend que le thread se termine? –

+3

C'est le cas, ce qui signifie qu'un seul thread est en cours d'exécution à la fois, totalement vaincre le but. –

Répondre

3

Vous devez soit plusieurs threads ou un appel à select/poll pour savoir quelles connexions ont des données non traitées. IBM has a nice example here, qui fonctionnera sur n'importe quelle saveur d'Unix, Linux, BSD, etc. (vous pourriez avoir besoin de différents fichiers d'en-tête selon le système d'exploitation).

En ce moment, vous lancez un thread, puis vous l'attendez immédiatement, ce qui entraîne une exécution séquentielle et annule complètement le but des threads.

+0

comment suis-je censé faire cela, pouvez-vous me donner un exemple? –

+0

Voici un exemple utilisant select, je suis toujours à la recherche d'un bon sondage, qui est la meilleure nouvelle option: http://www.gnu.org/s/libc/manual/html_node/Server-Example.html# Exemple de serveur –

+0

Voici un exemple avec 'poll', gestion des erreurs, le tout fonctionne: http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzab6/example.htm –

0

Une bonne approche serait de créer un thread qui n'accepte que les nouvelles connexions. C'est là que vous avez une prise d'écoute. Ensuite, pour chaque connexion acceptée, vous disposez d'un nouveau socket connecté, ce qui vous permet de générer un autre thread, en lui donnant comme paramètre le socket connecté. Ainsi, votre thread qui accepte les connexions ne se bloque pas et peut se connecter très rapidement à de nombreux clients. Les threads de traitement traitent les clients, puis ils sortent. Je ne sais même pas pourquoi j'ai besoin de les attendre, mais si vous le faites, vous pouvez le faire d'une autre manière, en fonction du système d'exploitation et/ou des bibliothèques que vous utilisez (messages, signaux, etc.). utilisé).

Si vous ne souhaitez pas générer un nouveau thread pour chaque client connecté, alors, comme l'a suggéré Ben Voigt, vous pouvez utiliser select. C'est une autre bonne approche si vous voulez faire un seul thread. Fondamentalement, toutes vos prises seront dans un tableau de descripteurs de socket et en utilisant select vous saurez ce qui s'est passé (quelqu'un connecté, socket est prêt pour la lecture/écriture, socket déconnecté, etc) et agir en conséquence.

Voici un exemple Partiel, mais cela fonctionne. vous acceptez simplement les connexions dans acceptConnections(), qui engendrera alors un thread séparé pour chaque client. C'est là que vous communiquez avec les clients. C'est à partir d'un code Windows que je traîne, mais il est très facile d'être réimplémenté pour n'importe quelle plateforme.

typedef struct SOCKET_DATA_ { 
    SOCKET sd; 
    /* other parameters that you may want to pass to the clientProc */ 
} SOCKET_DATA; 

/* In this function you communicate with the clients */ 
DWORD WINAPI clientProc(void * param) 
{ 
    SOCKET_DATA * pSocketData = (SOCKET_DATA *)param; 

    /* Communicate with the new client, and at the end deallocate the memory for 
     SOCKET_DATA and return. 
    */ 

    delete pSocketData; 
    return 0; 
} 

int acceptConnections(const char * pcAddress, int nPort) 
{ 
    sockaddr_in sinRemote; 
    int nAddrSize; 
    SOCKET sd_client; 
    SOCKET sd_listener; 
    sockaddr_in sinInterface; 
    SOCKET_DATA * pSocketData; 
    HANDLE hThread; 

    sd_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if (INVALID_SOCKET == sd_listener) { 
     fprintf(stderr, "Could not get a listener socket!\n"); 
     return 1; 
    } 

    sinInterface.sin_family = AF_INET; 
    sinInterface.sin_port = nPort; 
    sinInterface.sin_addr.S_un.S_addr = INADDR_ANY; 

    if (SOCKET_ERROR != bind(sd_listener, (sockaddr*)&sinInterface, sizeof(sockaddr_in))) { 
     listen(sd_listener, SOMAXCONN); 
    } else { 
     fprintf(stderr, "Could not bind the listening socket!\n"); 
     return 1; 
    } 

    while (1) 
    { 
     nAddrSize = sizeof(sinRemote); 
     sd_client = accept(sd_listener, (sockaddr*)&sinRemote, &nAddrSize); 

     if (INVALID_SOCKET == sd_client) { 
      fprintf(stdout, "Accept failed!\n"); 
      closesocket(sd_listener); 
      return 1; 
     } 

     fprintf(stdout, "Accepted connection from %s:%u.\n", inet_ntoa(sinRemote.sin_addr), ntohs(sinRemote.sin_port)); 
     pSocketData = (SOCKET_DATA *)malloc(sizeof(SOCKET_DATA)); 

     if (!pSocketData) { 
      fprintf(stderr, "Could not allocate memory for SOCKET_DATA!\n"); 
      return 1; 
     } 

     pSocketData->sd = sd_client; 
     hThread = CreateThread(0, 0, clientProc, pSocketData, 0, &nThreadID); 

     if (hThread == INVALID_HANDLE_VALUE) { 
      fprintf(stderr, "An error occured while trying to create a thread!\n"); 
      delete pSocketData; 
      return 1; 
     } 
    } 

    closesocket(sd_listener); 
    return 0; 
} 
+0

pouvez-vous s'il vous plaît me donner un exemple? Je ne vous comprends pas clairement. –

+0

Je ne pense vraiment pas que quelqu'un a suggéré d'utiliser un thread par client connecté ... –

+0

La bonne chose à propos d'un thread par client, c'est qu'il est facile de garder une trace de l'état indépendant par client. Cependant, la planification de tous les threads n'est pas aussi efficace que 'poll', et si vous avez des données partagées entre les clients, il est très facile d'introduire des conditions de course (et ajouter des mutex ou autres synchronisations pour améliorer les performances). –

0

Jetez un coup d'oeil ici: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/examples.html

en particulier le HTTP Server 3 exemple, c'est exactement ce que vous cherchez, tout ce que vous avez à faire est de changer ce code un peu pour vos besoins:) et votre fait

+0

donc async_accept ne bloque pas? –

+0

oui bien sûr, chaque fin chaque opération asynchrone est une opération non bloquante. Dans la plupart des cas, lorsque vous utilisez des opérations asynchrones (fonctions), vous n'avez même pas à utiliser de threads, cela peut simplifier votre conception + supprime les surcharges de changement de contexte provoquées par les threads ajoutés –

+0

Un serveur HTTP, où les connexions servir les demandes presque complètement indépendamment l'un de l'autre, n'est pas une bonne base pour utiliser un serveur de discussion. Mais cette page 'boost :: asio' a aussi un exemple de chat. –