Bonjour,
Je suis plutôt un débutant en c++ et j'ai quelques problèmes avec la manipulation de boost::thread et boost::socket.
En gros le principe de ce que je dois écrire :
J'ai un serveur qui écoute sur un port prédéfini en TCP et dès qu'il a une connection entrante, il refile la socket à un thread travailleur qu'il crée au passage. Celui s'occupe de la discussion avec le client.
Jusqu'ici tout est simple et ce que j'ai fait marche presque (comprenez, ca compile, ca se lance et ca marche jusqu'à la 4-5ème connexion ou le serveur plante avec l'erreur :
Apparemment, la socket s'est fermée avant d'arriver entre les mains du thread d'où le plantage (le code de l'erreur retournée est system:9 mais je n'en sais pas plus. Je n'ai toujours pas réussi à trouver une table de correspondance exhaustive des codes d'erreur de boost :s).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 terminate called after throwing an instance of 'boost::system::system_error' what(): Bad file descriptor
J'ai donc du faire un truc qui marche à peu près mais qui doit être affreusement mal foutu au niveau conceptuel.
Je vais vous résumer mon code : en gros mon serveur fait :
Et voici l'opérateur "()" du foncteur Tache :
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 void serveur::start_serveur() { boost::asio::io_service io_service; tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), monport)); for (;;) { tcp::socket socket(io_service); // On attend un client... acceptor.accept(socket); // Là on refile le travail à un thread travailleur Tache todo(&socket); boost::thread doit(todo); }
Bon, comme vous l'aurez remarqué (ou pas), une grosse partie du code vient directement des exemples de boost mais ma priorité pour le moment est de clarifier le fonctionnement des sockets et de faire une architecture serveur->thread_travailleur simple et fonctionnelle.
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 void Tache::operator() () { for (;;) { boost::array<char, 128> buf; boost::system::error_code error; size_t len = (*masocket).read_some(boost::asio::buffer(buf), error); if (error == boost::asio::error::eof) break; // Connection closed cleanly by peer. else if (error) throw boost::system::system_error(error); // Some other error. std::cout.write(buf.data(), len); } (*masocket).close(); }
Mon client, de son coté fait simplement une ouverture de socket puis une écriture :
Voilà un peu tout (et félicitations à ceux qui auront lu jusque là ).
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 using boost::asio::io_service io_service; tcp::resolver resolver(io_service); tcp::resolver::query query(argv[1], "daytime"); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end; tcp::socket socket(io_service); boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) { socket.close(); socket.connect(*endpoint_iterator++, error); } if (error) throw boost::system::system_error(error); boost::system::error_code ignored_error; std::string message = "HELLO"; boost::asio::write(socket, boost::asio::buffer(message),boost::asio::transfer_all(), ignored_error);
Mon gros problème est de comprendre les conditions de fermeture d'une socket. Dans mon esprit, les choses ne sont pas claires :
Je ne donne l'ordre à ma socket de se fermer qu'à la fin de la lecture du serveur mais il est clair que ca ne suffit pas : la socket se ferme d'elle même pour une raison inconnue.
À un moment, j'avais tenté l'opération inverse : le client écrit dans la socket et le serveur lit. À ce moment, le comportement était pour le moins étrange : si je demandais au thread principal de lire le socket, tout marchait mais si j'attendais que le thread travailleur s'occupe de la socket et qu'il la lise lui-même, j'obtenais un erreur (la socket s'étant fermée d'elle même et ce systématiquement ?!?!?).
Au passage :
- Si je ferme la socket avec close() d'un coté, cela ferme-t-il également la socket de l'autre coté (a priori je ne vois pas de raison pour que ce soit le cas mais bon...)
- Si j'appelle close(), cela appelle-t-il ~socket (si la méthode existe ?) par la même occasion ?
Merci beaucoup d'avance pour toute réponse qui me permettra d'y voir un peu plus clair...
Partager