Fichier texte: [libsocket.cc-TP5]
// -*- coding: latin-1 -*- //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // TP5 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //------------------------------------------------------------------------------ // connect(char* buf, int port) // // invoque l'appel système `connect' [cf. connect(2)] pour connecter cette // socket au serveur sur la machine dont le nom est dans `buf' et qui écoute sur // le `port'. // // ATTENTION: lorsqu'on appelle gethostbyname, s'il se produit une erreur, le // code d'erreur sera placé dans h_errno, et la fonction pour obtenir un char* // vers un message d'erreur approprié pour le code d'erreur n'est plus // `strerror' main `hstrerror'. // // Il faudra donc pouvoir distinguer les erreurs qui s'interprètent par // `strerror' et celles qui s'interprètent par `hstrerror'. Une manière très // simple de distinguer ces deux cas, c'est de stocker le deuxième cas sous une // forme négative: si le code est positif, alors il s'interprète par `strerror' // s'il est négatif, alors il s'interprète par `hstrerror' (mais il faut bien // sur enlever ce signe "moins" avant l'interprétation). // // Il vous faudra donc aussi modifier, la méthode `errmsg' pour qu'elle teste si // le code est positif ou négatif: dans le premier cas le message d'erreur // s'obtient avec `strerror', dans le second cas il s'obtient avec `hstrerror'. //------------------------------------------------------------------------------ int Socket::connect(const char* buf, int port) { ??? } //------------------------------------------------------------------------------ // connect(string host, int port) // // cette variante appelle la précédente en convertissant l'argument `host' de // type `string' en `char*' grâce à la méthode `c_str()' des `string'. //------------------------------------------------------------------------------ int Socket::connect(string host, int port) { ??? } //------------------------------------------------------------------------------ // read(char* buf, int n) // // lire sur la socket exactement `n' octets que l'on placera dans le buffer // pointé par `buf'. C'est ce qu'on a fait en TD avec la fonction `read_exact'. //------------------------------------------------------------------------------ int Socket::read(char* buf, int n) { ??? } //------------------------------------------------------------------------------ // readline(char* buf, int n) // // lire sur la socket jusqu'à la fin de la ligne (ou de fichier si le bout de la // ligne correspond au bout du fichier) et placer les octets dans le buffer // pointé par `buf'. Terminer cette séquence par '\0' pour qu'elle puisse être // utilisée comme une chaîne C. On ne mettra pas le caractère '\n' de fin de // ligne dans le buffer. // // L'argument `n' indique la taille maximale du buffer: si la ligne est trop // longue, on ne lira que n-1 octets et on placera '\0' dans le dernier octet. // on retournera alors la valeur 1 pour indiquer un succès intermédiaire: la // lecture c'est bien passée, mais on n'a pas encore tout lu. //------------------------------------------------------------------------------ int Socket::readline(char* buf, int n) { ??? } //------------------------------------------------------------------------------ // put_int8 (int n) // put_int16(int n) // put_int32(int n) // // écrire sur la socket un entier de 8, 16, ou 32 bits sous une forme normalisée // Si n est un entier, on peut obtenir l'octet le moins significatif de n de la // manière suivante: // // n & 0xFF // // En hexadécimal, F est la valeur 15, c'est à dire 4 bits tous à 1. 0xFF // représente donc 8 bits tous à 1. Avec (n & 0xFF) on obtient donc les // premiers 8 bits de n: les 8 bits les moins significatifs; c'est à dire // l'octet le moins significatif. // // Nous savons comment écrire un octet: il faut utiliser la méthode `write' avec // en 1er argument un pointeur vers l'octet à écrire (un buffer de longueur 1) // et en 2nd argument la taille du buffer, c'est à dire 1. // // Pour obtenir l'octet suivant de n, on décale les octets d'un octet vers les // moins significatifs, et on prend alors l'octet le moins significatif du // résultat: // // (n>>8) & 0xFF // // Pour des entiers de 8, 16 ou 32 bits, on répète cette procédure jusqu'à ce // qu'on ait écrit tous les octets de l'entier dans l'ordre du moins // significatif au plus significatif. //------------------------------------------------------------------------------ int Socket::put_int8(int n) { ??? } int Socket::put_int16(int n) { ??? } int Socket::put_int32(int n) { ??? } //------------------------------------------------------------------------------ // get_int8 (int& n) // get_int16(int& n) // get_int32(int& n) // // lire sur la socket un entier de 8, 16, ou 32 bits d'après la forme binaire // précédente. // // il faut se rappeler que nos fonctions put_int?(n) écrivent les octets de n du // moins significatif au plus significatif. Donc, si je lis un entier de 16 // bits, le premier octet lu est le moins significatif. // // si je lis d'abord l'octet le moins significatif dans b0, puis l'octet // suivant dans b1, comment reconstruire l'entier de 16 bits correspondant? // Il faut décaler b1 de 8 bit dans la direction des bits significatifs (vers la // droite) et il faut le concaténer avec b0. On peut faire cela de la manière // suivante: b0 | (b1<<8) //------------------------------------------------------------------------------ int Socket::get_int8(int& n) { ??? } int Socket::get_int16(int& n) { ??? } int Socket::get_int32(int& n) { ??? } //============================================================================== // class Client // // Cette classe offre une interface simplifiée pour fabriquer un client et le // connecter à un serveur. Elle hérite de `Socket' pour intégrer la socket avec // laquelle on va se connecter au serveur. //============================================================================== //------------------------------------------------------------------------------ // Client() le constructeur //------------------------------------------------------------------------------ Client::Client() ??? //------------------------------------------------------------------------------ // run(char* host, int port) // // utilise les méthodes de "Socket" pour établir une connexion à un serveur. // puis invoque la méthode "interaction" pour traiter cette connexion, puis // ferme la connexion. //------------------------------------------------------------------------------ int Client::run(const char* host, int port) { ??? } //------------------------------------------------------------------------------ // run(string host, int port) // // variante de la précédente avec un `string' en premier argument //------------------------------------------------------------------------------ int Client::run(string host, int port) { ??? }