begin process at 2010 02 10 13:38:15
  Trouver un code source :
 
dans
 
Accueil > Forum > 

C++ & C++ .NET

 > 

Windows

 > 

Réseau & Internet

 > 

Thread principal bloqué après un appel à recv dans un thread distinct


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

Thread principal bloqué après un appel à recv dans un thread distinct

lundi 20 octobre 2008 à 10:16:49 | Thread principal bloqué après un appel à recv dans un thread distinct

patochdu77

Bonsoir !

Je m'en remet à vous après de longues heures de recherche et ceci depuis un peu plus d'une semaine pour résoudre un problème.
Je developpe un jeu vidéo type rpg en ligne (du genre de ceux très prisés de nos jours) en C++, avec pour API graphique DirectX (natif), et la librairie Winsocks pour le réseau.

Jusqu'à maintenant j'utilisait des sockets bloquantes ainsi que la fonction de multiplexage select afin de pouvoir envoyer mes requêtes au serveur et en recevoir les réponses de façon à ne pas bloquer le rendu graphique.
Seulement, à moins que je ne me sois fourvoyé, il me semble qu'il faut appeler celle-ci avec une structure timeval correspondant à un intervalle de temps non nul afin de ne pas bloquer, soit au minimum à peu près 10 ms.
Mon soucis avec cette solution c'est que ce temps accumulé à chaque appel de select, a un impact, même s'il est minime, sur le temps de boucle de mon programme.
D'où ma première question, devrais-je négliger ce temps ou aborder le problème d'une autre façon ?

Depuis j'ai essayé une autre méthode, effectuer l'envoi et la reception des données dans un thread distinct. C'est ici que réside mon plus gros soucis, une fois que l'utilisateur a entré ses identifiants je lance le thread qui effectue les opérations d'authentification. La fonction connect est appelée avec succès et ne bloque pas un poil le thread principal (de rendu), en revanche après l'envoi des identifiants, j'appelle la fonction recv afin de recevoir la réponse et cet appel bloque mon thread principal, et donc le rendu pendant un temps court (1 à 2 sec).
Afin de m'assurer que le problème était bien du à l'appel de recv, j'ai rajouté un Sleep de quelques secondes à mon serveur entre la reception des identifiants et l'envoi de la réponse, on constate bien que recv bloque son propre thread (normal) et le thread principal donc pas de rendu pendant ce temps là =/

J'espère avoir été le plus clair possible, dans le cas contraire ou s'il manque des indications, dites le moi, en attendant voici le code associé au problème.
Merci d'avance à tous.

Le client
Code :
//La fonction principale du thread 
DWORD WINAPI ConnectionThread(LPVOID lParam)
{
t_client *m_client = (t_client*)lParam;
m_client->Connect();
return 0;
}

//La fonction appelée lorsque les identifiants de l'utilisateur ont été entrés lançant le thread
void t_client::StartConnection(string username, string password)
{
m_userinfo = username + ";" + password;
CreateThread(NULL, 0, ConnectionThread, this, 0, &m_thread);
}

//La fonction appelée par le thread
void t_client::Connect()
{
//On récupère l'IP du serveur à partir du nom de domaine
struct hostent *host;
host = gethostbyname((char *)m_hostname);
SOCKADDR_IN sin;
sin.sin_addr = *((struct in_addr *)host->h_addr);
sin.sin_family = AF_INET;
sin.sin_port = htons(3000);
//On créé le socket avec ces infos
m_socket = socket(AF_INET, SOCK_STREAM, 0);

//On procède à la connexion du client
int success = 0;
success = connect(m_socket, (SOCKADDR *)&sin, sizeof(sin));
if (success == - 1)
{
m_connected = false;
}
else
{
m_connected = true;
//J'ai testé en mode non bloquant avec les deux lignes suivantes, et ça fonctionne
//u_long val = 0;
//ioctlsocket(m_socket, FIONBIO, &val);

//Envoi des identifiants au serveur
Send(m_userinfo);

//Reception de la réponse
s_data login;
login = Receive();
if (login.val.front() == "ok")
{
//L'authentification a réussi
m_authentificated = true;
}
else
{
//L'authentification a échoué, on de deconnecte
m_authentificated = false;
m_connected = false;
}
}
}
Le serveur:
Code :
void t_server::ProceedConnection()
{
SOCKADDR_IN sin;
int sin_size = sizeof(struct sockaddr_in);

//On accepte le client
int client = accept(m_socket, (SOCKADDR *)&sin, (int *)&sin_size);
if(client != INVALID_SOCKET)
{
//Reception des identifiants de connexion
string user_info = "", username = "", password = "";
user_info = Receive(client);
int i = 0;
while ((i < user_info.length()) && (user_info[i] != ';'))
{
username = username + user_info[i];
++i;
}
++i;
while (i < user_info.length())
{
password = password + user_info[i];
++i;
}
cout << "\nDemande de connexion de ";
cout << username << endl;
int login = m_database->User_Login(username, password);
if (login)
{
//Le client existe, on effectue un sleep pour mettre en évidence le blocage puis on envoie la confirmation
Sleep(10000);
Send(client, "login;ok");
++m_nbClients;
m_clients[m_nbClients - 1].name = username;
m_clients[m_nbClients - 1].desc = client;
cout << "Connexion acceptee" << endl;
}
else
{
//Les identifiants sont érronés, on envoie la réponse au client
Send(client, "error");
cout << "Connexion refusee, identifiants incorrects" << endl;
}
}
}
mardi 21 octobre 2008 à 01:27:33 | Re : Thread principal bloqué après un appel à recv dans un thread distinct

f_l_a_s_h_b_a_c_k

ses comme lire un fichier byte par byte ses plus long que de lire un buffer[1024] d un coup

example 1024??


 int rcvtimeo = 5000 ; // 5 sec  receive time
 
    if( setsockopt( m_s , SOL_SOCKET , SO_RCVTIMEO , (const char *)&rcvtimeo , sizeof(rcvtimeo) ) == SOCKET_ERROR)
 
   
   char buf[1024];
       
        while(1)
        {
            //Sleep(1);
            iRet =     recv( m_s , buf , sizeof( buf ) , 0 ) ;

             

            if( iRet == SOCKET_ERROR )
            {
                dwErr = WSAGetLastError() ;
                printf( "Error recv() = %ld \n" , dwErr ) ;
                continue ;
            }
           
if(iRet>=1024) { ///buffer plein
//utiliser le  buffer!
//decoder une structure ou byte par byte
printf("%s",buffer);

iRet=0;
}


je sais pas si tu pas gagner de la vitesse comme ca?


}
mardi 21 octobre 2008 à 18:26:22 | Re : Thread principal bloqué après un appel à recv dans un thread distinct

patochdu77

Salut à toi, merci d'avoir pris le temps de me répondre.

Si j'ai bien compris tu pense donc que la taille des données implique que la durée de reception est importante, donc le blocage serait du uniquement au temps de reception ?
Mais il me semble que ce n'est pas le cas car si je ne l'ai pas précisé, le blocage (l'arret du rendu) est observable dès l'appel à recv, alors que le serveur envoie la réponse environ 10sec après (grâce au sleep que j'ai placé pour mettre en évidence le problème). C'est donc le temps d'attente des données avant lecture qui pose problème.

Je rajouterai qu'en remplaçant l'appel à recv par une fonction testant le descripteur de socket à l'aide d'un select tant qu'il n'y a rien à lire, on constate le meme blocage, sur la fonction select.
Peut-être qu'en utilisant une socket non bloquante et en utilisantévénements WSAAsyncSelect ?

Enfin le soucis final est que logiquement une application multithread permet de se passer du select, des sockets non bloquantes et autres... Aurais-je mal compris quelque chose, ou est-ce une erreur de programmation?


Cette discussion est classée dans : client, thread, sin, username, identifiants


Répondre à ce message

Sujets en rapport avec ce message

multi thread avec librairie phtread -> help please [ par davwart ] Hello all.j'essaie de faire un chat en mode console en utilisant la librairie pthread.h.mon serveur a une fonction main qui lance un thread d'ecoute e PROBLEME CLIENT SERVER [ par zzzzzz ] Mon client marche c sur et il envoie bien abcd mais monserver marche po je suis debutant en server socket... :(je sais pas comment faire en sorte que Probleme de Client Serveur [ par Krox68 ] voila jaimerais faire un programme client qui puisse se connecter a ce serveur : #include void main(){ WSADATA WSAData; WSAStartup(MAKEWORD(2,0), &WS Affichage image dans zone client + Thread [ par PoluxProg ] Pour afficher une image dans la zone client, j'utilise ce code qui marche plutôt bien: CBitmap *pImage=new CBitmap; pImage->LoadBitmap(IDB_IMAGE); client serveur [ par elanspeech ] Bonjour,Je suis en train de programmer un petit client serveur en C pour windows avec dev-c++. J'obtiens l'erreur suivante a la compilation : D:\DEV-C thread ne répondant pas sous MFC [ par seito ] bonjours,je suis en train de concevoir une application qui me permet d'éffectuer un chat en réseau sous "Visual C++ 6.0" le problême c'est que quand j Client - serveur C++ avec thread [ par nono_in_maribor ] Bonjour!!Voila, je previens tout de suite je ne suis pas un pro du c++. Mon probleme est le suivant : j'ai fait un client-serveur en c++ (sous devc++) Client/Serveur, encore..... [ par glubust ] Je veux faire fonctionner une application client/serveur sous UNIX (client) et WINDOWS (serveur).Le programme client envoi une simple requête au serve Socket [ par c2millet ] Bonjour à tous,je voudrais dans un premier tps si qqun a ou connais une doc sur les sockets. Ensuite, g un petit pb. g réalisé un serveur qui lit sur Thread, Client/Serveur VC++.Net et avec WinForms ( pas d'MFC ) [ par lacousine ] Bonjour,j'ai développé un serveur qui accept plusieurs clients avec des sockets. Voici mes problèmes: lorsque je veux mettre fin à mon serveur et qu'i


Nos sponsors


Sondage...

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,702 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales