Bonsoir,
Je code en ce moment un serveur TCP pour un MMORPG.
Ayant comme idée en tête que même si je ne suis pas vraiment bon en C++, je veux une bonne synchronisation entre ce que un joueur enverra, et que tout les joueurs sur la même map recoivent ce que le serveur aura à transmettre, en même temps.
Voici une esquisse (Picasso n'est-il pas?): http://imageshack.us/photo/my-images/194/37628850.png/
Mon serveur a comme architecture:
Chaque serveur, possede son propre thread.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 - LoginServer Ecoute les connections, il sert a ce que les joueurs s'identifie, gère les banIP, choix du World, et du channel, et de son personnage. - WorldServer Il contient X channel, et est unique (nom). Il recoit le client apres connection au login, pour alleger ce dernier (je pense ?) Il doit egalement gerer une PARTIE des packets recus par les clients - Channel Server Ce serveur gère le "in-game". Deplacements, attaques, blablatage.
(Je pense que c'est une meilleure option que d'avoir 1 thread par client, car si jamais j'ai 5000 clients, je pense avoir un probleme, non ? Corrigez moi si c'est mieux d'avoir des milliers de threads, merci)
Donc je reviens à mon image.
Les clients vont envoyer des centaines de packets en meme temps.
Comment est-il possible de faire, pour que certains packets soient gerer par Login, d'autres par world, et d'autres par channel ?
Imaginons 1000 joueurs:
- - LoginServer: 1000 joueurs, mais une gestion de TRES TRES peu de packets
- - WorldServer: 500 joueurs (si j'en ai deux par exemple.), Avec plus de packets.
- - Channel Server: 250 (2.) Ici, c'est un peu comme la centrale fukushima avec un tsunami en face.
Exemple:
- Je suis sur mn perso, je me deplace à gauche => Gestion par Channel X (X etant en fonction du channel sur lequel je me trouve)
- Je quitte ma guilde => Gestion par World.
- Je me deconnecte => Gestion par Login
Voici le LoginServer, quand il démarre (JE n'ai fait aucun test de connexions, car je ne RECV pas encore sur 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 XServer::LoginServer::LoginServer() { running = true; _nbClients = 0; _acceptClients = true; bool stop = false; WSADATA WSAData; WSAStartup(MAKEWORD(2,0), &WSAData); if((sock = socket(AF_INET, SOCK_STREAM, 0)) == (unsigned int)INVALID_SOCKET) { cout << "ERROR: Could not start LoginServer" << endl; stop = true; } SOCKADDR_IN sin; sin.sin_family = AF_INET; sin.sin_port = htons(LS_PORT); sin.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sock, (SOCKADDR *) &sin, sizeof(sin)) == SOCKET_ERROR && !stop) { cout << "ERROR: LoginServer couln'd bind socket parameters" << endl; stop = true; } if(listen(sock, 5) == SOCKET_ERROR && !stop) { cout << "ERROR: LoginServer couln'd listen on port " << LS_PORT << endl; stop = true; } if((Lthread = CreateThread(NULL, 0, ls_Listen, this,0, NULL)) == NULL && !stop) { cout << "ERROR: LoginServer thread starting failed (ls_Listen)" << endl; stop = true; } /* if((Rthread = CreateThread(NULL, 0, ls_Recv, this,0, NULL)) == NULL && !stop) { cout << "ERROR: LoginServer thread starting failed (ls_Recv)" << endl; stop = true; } */ if(!stop) { cout << "INFO: LoginServer is up and listening on port " << LS_PORT << endl; } }
Et voici la fonction ls_Listen:
La ou je bug un peu, c'est que pour la fonction recv, il faut préciser le socket. Et je pense que c'est couteux de faire une boucle (de meme que cest trop couteux de demarrer 1000 threads.
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 DWORD WINAPI ls_Listen(LPVOID para) { XServer::LoginServer *ls = (XServer::LoginServer *) para; SOCKADDR_IN csin; SOCKET csock; int size = sizeof(csin); while(1) { csock = accept(ls->sock, (SOCKADDR *) &csin, &size); if(!ls->acceptingClients()) { int a = CONNECT_REFUSED; send(csock, (char*)&a, sizeof(int), 0); shutdown(csock, 2); } else if(ls->getMaxClients() <= ls->nbClients()) { int a = SERVER_FULL; send(csock, (char*)&a, sizeof(int), 0); shutdown(csock, 2); } else { if(csock >= 0) { printf("LoginServer: Client connection (IP: %s; Port: %d)", csin.sin_addr, csin.sin_port); Client *c = new Client((std::string)inet_ntoa(csin.sin_addr), (int)ntohs(csin.sin_port)); c->Sock(csock); ls->AddClient(c); Packet *p = new Packet(); p->setInfo(1, 0); c->writePacket(p); } else { shutdown(csock, 2); } } } }
Donc, au final, j'aimerais pouvoir demarrer dans un premiers temps un thread dans LoginServer (ce qui est commenté) qui recevra les messages, sans pour autant faire une mega boucle sur 1000 connections.
-------------------------------------
Cette partie, est à oublier
Etant donné que j'avais pas encore réfléchi au probleme posé...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Client *c = new Client((std::string)inet_ntoa(csin.sin_addr), (int)ntohs(csin.sin_port)); c->Sock(csock); ls->AddClient(c);
Sans etre chiant (un peu quand meme), je ne suis pas vraiment bon. une expliquation pro = je vais rien comprendre
Merci d'avance à ceux qui aurant le courage de m'aider
nico.
Partager