Remarque

La méthode de lecture des exemples, utilisés dans ce chapitre, fonctionne parfaitement avec un client tel que la version Linux de la commande telnet, car ce client envoie (par défaut) ligne par ligne, dans le canal de communication TCP, ce qui est saisi. Par contre, cela ne fonctionne pas avec la version Windows de la commande telnet, car cet autre client envoie (par défaut) caractère par caractère au fur et à mesure de la saisie.

Comment régler le problème ?

Il faut partir du principe qu'une réception d'un flux TCP peut être fragmentée en plusieurs morceaux de taille (tous de taille inférieure au tampon passé à la fonction read). Une ligne doit donc être lue via une boucle de read qui remet bout à bout chaque morceau lu jusqu'à réception du caractère de fin de ligne.

Pour être complet, il faut également prévoir le cas où on commencerait à recevoir quelques caractères de la ou des lignes suivantes qu'il convient donc de conserver et d'isoler de la ligne précédente.

Sans gestion de stream Avec gestion de stream

En multi-processus

Voir les solutions améliorées du TP n°2 question n°2.

En multi-thread

Voir les solutions améliorées du TP n°2 question n°3.

En mono-tâche

Voir les solutions améliorées du TP n°2 question n°4.

En langage C, il existe le type FILE défini dans stdio.h qui offre plusieurs possibilités dont les suivantes :

  • Utilisation de la fonction fgets(char *buffer, int size, FILE *stream) qui lit au plus size - 1 caractères depuis stream et les place dans le tampon pointé par buffer. La lecture s'arrête après EOF ou un retour-chariot. Si un retour-chariot (newline) est lu, il est placé dans le tampon. Un octet nul « \0 » est placé à la fin de la ligne transformant ainsi le contenu du buffer en chaine de caractères. La fonction renvoit le pointeur buffer si elles réussissent, et NULL en cas d'erreur, ou si la fin de fichier est atteinte avant d'avoir pu lire au moins un caractère.
  • Utilisation de la fonction feof(FILE *stream) qui teste l'indicateur de fin de fichier du flux pointé par stream, et renvoie une valeur non nulle si cet indicateur est actif.
  • Utilisation de la fonction fclose(FILE *stream) qui ferme le stream ainsi que le descripteur de fichier qui se cache derrière lui.

On peut associer à un descripteur de fichier une gestion de stream via la fonction fdopen(int fd, const char *mode) qui retourne un pointeur vers un FILE si l'association s'est faite avec succès. Le premier argument de la fonction est le descripteur de fichier. Le second argument est une chaine de caractère indiquant le mode d'utilisation, celui-ci devant être compatible avec le fonctionnement du descripteur de fichier.

Exemple :

#include <stdio.h>

void communication_serveur(int fd) {
	FILE *stream;
	char buffer[1024];

	stream=fdopen(fd,"rb");
	if (stream!=NULL) {
		while (!feof(stream)) {
			fgets(buffer,sizeof(buffer),stream);
			write(fd,buffer,strlen(buffer));
		}
	}
}
				

Remarque :

Même si cette méthode peut être agréable à utiliser et fonctionne très bien en mono-client et en multi-client quand on utilise le multi-processus ou le multi-thread, il ne faut pas perdre de vue que les fonctions, de lecture de stream, telles que fgets sont, par défaut, bloquantes car elles utilisent des boucles de read et peuvent donc poser des problèmes dans une programmation multi-client/mono-tâche utilisant la fonction select.