libsocket.cc-TP5


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)
{
  ???
}