Fichier texte: [libsocket.cc]
// -*- coding: latin-1 -*- #include "libsocket.hh" using std::string; //------------------------------------------------------------------------------ // pour les includes de la bibliothèque C, il faut indiquer à C++ qu'il s'agit // de fonctions C et non de fonctions C++. Pour cette raison, il faut mettre // les includes à l'intérieur d'un bloc spécial: // // extern "C" { ... } //------------------------------------------------------------------------------ extern "C" { ??? } //============================================================================== // class ErrInfo // // que faire quand il se produit une erreur? Différentes action peuvent être // envisagées: // // - ne rien faire // - recommencer l'opération, essayer autrement, ou faire autre chose // - afficher un message sur un terminal (par exemple avec `perror') // - ajouter un message à un fichier de log // - afficher un message dans une fenêtre graphique // - etc ... // // cette décision dépend de l'application et varie d'une application à une // autre. Si nous voulons une bibliothèque qui soit utilisable par n'importe // quelle application, il faut qu'elle se contente de donner à l'application // les informations sur une erreur, et c'est l'application elle-même qui // choisira quoi faire de ces information. // // La classe `ErrInfo' est un conteneur destiné à prendre note des informations // relatives à une erreur: le nom de la procédure dans laquelle s'est produite // cette erreur (champ _proc) et le code de cette erreur (champ _code). //============================================================================== //------------------------------------------------------------------------------ // ErrInfo() le constructeur //------------------------------------------------------------------------------ ErrInfo::ErrInfo() ??? //------------------------------------------------------------------------------ // errset(int code, string proc) // // prend note, dans les champs _proc et _code de l'objet ErrInfo, d'une erreur // s'étant produite dans la procédure nommée `proc' et caractérisée par le code // d'erreur `code' //------------------------------------------------------------------------------ void ErrInfo::errset(int code, string proc) { ??? } //------------------------------------------------------------------------------ // errmsg(char* buf, int n) // // écrit dans le buffer `buf' de taille maximale `n' un message d'erreur appro- // prié à l'erreur dont les informations sont enregistrées ici. Vous vous // servirez des fonctions `snprintf' etz `strerror' pour formatter ce message // d'erreur. On voudrait un message ayant la forme de ceux produit par `perror' // par exemple: // // bind: permission refusée //------------------------------------------------------------------------------ void ErrInfo::errmsg(char* buf, int n) { ??? } //============================================================================== // class Socket // // Cette classe offre des méthodes d'utilisation simplifiée pour faire des // opérations réseau. Elle hérite également de `ErrInfo' pour nous permettre de // prendre note facilement des informations relative à une erreur survenant // durant une de ces opérations. La classe `Socket' contient un champ `_fd' // dans lequel on mettra le descripteur correspondant à la socket. Les méthodes // ci-dessous retournent 0 en cas de succès. En cas d'échec elles retournent -1 // après avoir utilisé la méthode `errset' (voir ErrInfo) pour noter les détails // de l'erreur. //============================================================================== //------------------------------------------------------------------------------ // Socket() le constructeur //------------------------------------------------------------------------------ Socket::Socket() ??? //------------------------------------------------------------------------------ // socket() // // invoque l'appel système `socket' [cf. socket(2)] pour créer une socket: // (1) dans le domaine de l'internet, (2) orientée "flux d'octets", et met son // descripteur dans le champ `_fd'. Pour indiquer à C++ que vous voulez appeler // la fonction globale `socket' plutôt que la méthode `socket' de la classe, il // faut écrire `::socket' //------------------------------------------------------------------------------ int Socket::socket() { ??? } //------------------------------------------------------------------------------ // close() // // invoque l'appel système `close' [cf. close(2)] pour fermer la socket et // libérer les ressources qui lui sont associées. //------------------------------------------------------------------------------ int Socket::close() { ??? } //------------------------------------------------------------------------------ // bind(int port) // // invoque l'appel système `bind' [cf. bind(2)] pour lier la socket au `port' // sur toutes les interfaces. Cette méthode remplit une addresse de socket // `struct sockaddr_in' [cf. ip(7)], puis l'utilise dans l'appel à `::bind'. // N'oubliez pas les normalisations nécessaires à effectuer avec `htons' ou // `htonl' [cf. htons(3)]. //------------------------------------------------------------------------------ int Socket::bind(int port) { ??? } //------------------------------------------------------------------------------ // listen(int backlog) // // invoque l'appel système `listen' [cf. listen(2)] pour indiquer qu'on va // écouter sur cette socket; c'est à dire qu}on va y attendre des demandes de // connexion de clients avec `accept'. L'argument `backlog' est optionel et // prend la valeur 10 par défaut quand il est omis (voir déclaration dans // libsocket.hh). //------------------------------------------------------------------------------ int Socket::listen(int backlog) { ??? } //------------------------------------------------------------------------------ // accept(Socket& client) // // invoque l'appel système `accept' [cf. accept(2)] pour attendre et accepter // une connexion d'un client. Il met alors le descripteur de la connexion dans // le champ `_fd' de la socket `client' passée en argument. // // Notez que l'objet Socket client doit bien entendu avoir été déclaré (et donc // instantié) avant d'appeler cette méthode à laquelle on le passe en argument. //------------------------------------------------------------------------------ int Socket::accept(Socket& sock) { ??? } //------------------------------------------------------------------------------ // write(const char* buf, int n) // // écrire sur la socket exactement `n' octets pointés par `buf'. C'est ce qu'on // a fait en TD avec la fonction `write_exact'. //------------------------------------------------------------------------------ int Socket::write(const char* buf, int n) { ??? } //------------------------------------------------------------------------------ // write(const char* buf) // // cette variante appelle la méthode précédente en calculant ell-même la // longueur de la chaîne de caractères. //------------------------------------------------------------------------------ int Socket::write(const char* buf) { ??? } //------------------------------------------------------------------------------ // write(string buf) // // cette variante appelle la précédente en convertissant l'argument `buf' de // type `string' en `char*' grâce à la méthode `c_str()' des `string'. //------------------------------------------------------------------------------ int Socket::write(string buf) { ??? } //============================================================================== // class Server // // Cette classe offre une interface simplifiée pour fabriquer un serveur et le // mettre en service en réseau. Elle hérite de `Socket' pour intégrer la socket // sur laquelle on va accepter les demandes de connexion de clients. //============================================================================== //------------------------------------------------------------------------------ // Server() le constructeur //------------------------------------------------------------------------------ Server::Server() ??? //------------------------------------------------------------------------------ // run(int port) // // utilise les méthodes définies précédemment pour créer la socket, la lier au // `port' sur toutes interfaces, et déclarer qu'on va écouter sur elle et y // attendre les demandes de connexion de clients. // // ensuite, appelle la méthode `loop()' pour entamer la boucle de service des // clients //------------------------------------------------------------------------------ int Server::run(int port) { ??? } //------------------------------------------------------------------------------ // loop() // // méthode virtuelle (donc redéfinissable dans les classes dérivées) // implémentant la boucle infinie qui accepte une connexion d'un client, invoque // la méthode `interaction' pour traiter cette connexion, puis ferme la // connexion. //------------------------------------------------------------------------------ int Server::loop() { ??? }