Client Serveur multithread : problème
Bonjour,
J'écris un petit jeu multijoueurs et j'ai un problème avec le serveur (ou le client je ne sais pas vraiment justement).
Pour chaque joueur (chaque client) un nouveau thread est lancé, mais lorsque qu'un client envoi une donnée au serveur, tous les threads la recoivent :/
Le but est d'envoyer au serveur chaque action (touche appuyée, touche relachée, ...), qui lui calcule les mouvements et renvoi les nouvelles coordonées.
Si vous trouvez que cette architecture / méthode est mauvaise ou si vous avez des remarques quelconque n'hésitez pas!
Comment ça marche, au niveau du serveur j'ai 2 classes :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Server {
public:
Server();
~Server();
...
private:
int nbrConnexions;
int nbrPlayers;
SOCKET serverSocket;
SOCKADDR_IN serverSin;
vector<Player*> players;
...
}; |
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Player {
public:
int numPlayer,x,y,state;
SOCKET sock;
SOCKADDR_IN sin;
Player();
~Player();
...
void start();
DWORD WINAPI threadFunction();
static DWORD WINAPI run(LPVOID lpParam);
...
private:
DWORD baseTickCount;
DWORD threadId;
HANDLE threadHandle;
...
}; |
Sur le serveur j'ouvre le socket pour se connecter :
Code:
1 2 3 4 5 6 7 8 9 10
| WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
serverSin.sin_addr.s_addr = INADDR_ANY;
serverSin.sin_family = AF_INET;
serverSin.sin_port = htons(PORT);
bind(serverSocket, (SOCKADDR *)&serverSin, sizeof(serverSin));
listen(serverSocket, 0); |
Puis j'attend les connections :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| //preparation for an incoming player
Player *p = new Player();
p->numPlayer = nbrConnexions;
players.push_back(p);
int sinsize = sizeof(p->sin);
while(1) {
if( (p->sock = accept(serverSocket, (SOCKADDR *)&p->sin, &sinsize) ) != INVALID_SOCKET ) {
cout << "New connexion : " << inet_ntoa( p->sin.sin_addr ) << ":" << ntohs( p->sin.sin_port ) << endl;
p->start();
nbrConnexions++;
if (nbrConnexions == nbrPlayers) {
break;
} else {
p = new Player();
p->numPlayer = nbrConnexions;
players.push_back(p);
}
}
} |
p->start() lance le thread du joueur :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| void Player::start() {
threadHandle = CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)run, this, 0, &threadId);
}
DWORD WINAPI Player::run(LPVOID lpParam) {
Player* p = (Player*)lpParam;
return p->threadFunction();
}
DWORD WINAPI Player::threadFunction() {
cout << "Thread created for player " << numPlayer << endl;
...
while(1) {
recv(sock, (char*)&gm, sizeof(GameMove), 0);
...
cout << "received code " << gm.code << " at time " << getTime() << " from player " << numPlayer << endl;
}
terminate();
return 0;
} |
A chaque code envoyé par un client tous les threads affichent le message "received code XXX at time XXX from player X", où le numéro de joueur est correct (chaque thread recoit comme si "leur" client avait envoyé le code)
Le client :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Client {
public:
Client();
virtual ~Client();
...
bool connexion(char* address);
...
private:
...
int x, y;
int state, nbrPlayers, numPlayer;
SOCKET sock;
SOCKADDR_IN sin;
}; |
Code:
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
| bool Client::connexion(char* address) {
...
cout << "Connexion...";
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
sin.sin_addr.s_addr = inet_addr(address);
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sock = socket(AF_INET,SOCK_STREAM,0);
bind(sock, (SOCKADDR *)&sin, sizeof(sin));
if (connect(sock, (SOCKADDR *)&sin, sizeof(sin)) == -1 ) {
Console::pos(55, 11);
cout << "Unable to connect";
return false;
}
//lecture du numéro de joueur + version
...
Console::pos(55, 11);
cout << "Welcome player " << numPlayer;
//attente des joueurs, dès que l'on reçoit les DataGame c'est bon
...
return true;
} |
Ensuite à chaque action sur le client j'execute ce code :
Code:
1 2 3 4 5 6 7
| void Client::keyboardEvent(int code) {
GameMove gm;
gm.code = code;
...
//on envoi au serveur le mouvement
send(sock, (char*)&gm, sizeof(GameMove), 0);
} |
En fait c'est la 2ème version de cette appli que je fait, la première avait été mal conçue et les joueurs pouvaient avancer plus vite si ils avaient un meilleur ping lol. Je n'avais pas ce problème sur la v1 et le code des sockets a été quasiement copié collé.
J'ai essayé plusieurs choses mais impossible de savoir d'où vient ce problème :/, si vous avez une idée ou si vous avez remarqué quelque chose qui ne va pas help merci :)