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
Le serveur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 //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; } } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 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; } } }
Partager