Premier Programme
tout texte à l’intérieur de /* et */ est un commentaire
HelloWorld.c
/* this is our first C program,
* it will display a message
*/
#include <stdio.h>
importe un fichier
d’en-tete contenant
les définitions de int main()
{
la bibliothèque E/S printf("Hello, World\n");
}
bloc d’instructions délimité par { et }
(corps de fonction, boucle, condition ...)
Figure 1: gcc -Wall HelloWorld.c pour compiler
Introduction au langage C
• langage de programmation impératif, typage faible
• largement utilisé dans la conception/programmation des
systèmes UNIX
caractéristiques
• chaque variable/fonction doit avoir été définie avant de servir
• sources constituées de fichiers de définitions (.h) et de fichiers
d’ implémentation (.c)
• chaque programme possède une fonction principale (main) qui
est appelée par le système
• pas de type “chaı̂ne” : tableaux de caractères + bibliothèques
ouvrage de référence :
• “Le langage C, 2o édition (norme ANSI)”, B.W. Kernighan &
D.M. Ritchie, Prentice Hall (isbn: 2-225-83035-5)
1
Second Programme : l’Écouteur
fichiers :
• listener.c : établissement de la connexion réseau
• receive echo.c : fonction appelée une fois la connexion établie
• minidebug.h : macros pour faciliter la mise au point (compiler
avec l’option NO DEBUG pour la version finale :)
compilation : gcc listener.c receive echo.c -o listener
utilisation :
• lancer le programme (./listener)
• sur une autre console, telnet localhost 12345
• les messages tapés depuis telnet sont répétés par listener
Kit de survie
affectation : variable = expression
• ne pas confondre avec la comparaison d’égalité ==
conditions : if ( expression ) commandes else commandes
• commandes ::= instruction; | { déclarations instructions }
• la partie else est optionnelle
• une expression est vraie si sa valeur 6= 0
• voir aussi switch et test-expr ?if-expr :else-expr
boucles : while ( expression ) commandes
• répète les commandes tant que l’expression est vraie,
• while(1)commandes boucle à l’infini
• voir aussi for, do .. loop, do .. while, break et continue
http://www.linux-kheops.com/doc/ansi-c/
3
Printed by Sylvain Martin
Oct 09, 01 10:11 listener.c Page 1/1
#include <sys/socket.h>
#include <netinet/in.h>
#include "minidebug.h"
#define LOCAL_PORT 12345
void receive_datas(int fd);
main()
{
int masterfd, datafd;
struct sockaddr_in listen_addr={
sin_family: AF_INET, sin_port:htons(LOCAL_PORT)
};
DD("Initialising connection ...\n");
masterfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (masterfd == −1) FATAL("socket");
listen_addr.sin_addr.s_addr=INADDR_ANY;
if (bind(masterfd,(struct sockaddr*)&listen_addr,sizeof(listen_addr))==−1)
FATAL("bind");
listen(masterfd,2);
DD("waiting for a talker on port %i...\n", LOCAL_PORT);
datafd=accept(masterfd,NULL,NULL);
close(masterfd);
DD("ready to receive datas\n");
receive_datas(datafd);
DD("all done\n");
}
Tuesday October 09, 2001 listener.c 1/1
4-2
Printed by Sylvain Martin
Oct 09, 01 10:05 receive_echo.c Page 1/1
void receive_datas(int fd)
{
char buffer[257];
int len=1;
memset(buffer,0,256);
while(len!=0)
{
len=recv(fd,buffer,256,0);
buffer[len]=0;
printf("received: %s\n",buffer);
}
}
Tuesday October 09, 2001 receive_echo.c 1/1
4-1
Autres Remarques ...
paramètres :
• ici, des constantes (LOCAL PORT) → il faut recompiler si on
désire faire tourner le serveur sur un autre port :-(
• si on déclare main(int argc, char* argv[]), on peut
récupérer les arguments de la ligne de commande et s’en servir
comme paramètre.
makefile :
• automatiser le processus de compilation
• pour chaque fichier à générer, une règle donnant la cible, les
dépendances (fichiers utilisés) et les commandes de compilation
• make en ligne de commande pour compiler le tout :)
Remarques ...
listen addr Il s’agit d’une structure contenant les paramètres
nécessaires à bind pour créer le TSAP (adresse IP, no de port, type
d’adresse).
• le champ sin zero doit être initialisé à 0
• le champ sin port doit être passé en network order → htons
• bind attend une structure de type sockaddr → casting
(transtypage) nécessaire (struct sockaddr*)
Locals
masterfd = -1073746664
datafd = 1073795440
sin_family = 2
sin_port = 14640
listen_addr =
sin_addr = s_addr = 0
sin_zero = "\000\000\000\000\000\000\000"
5
Pointeurs
Variables dont la valeur est l’adresse en mémoire d’un autre
élément (variable ou fonction).
Utilité :
• manipulation des chaı̂nes de caractères (=ptr vers un tableau)
• arguments passés par variable : int x; scanf("%i",&x);
• portée dynamique : groupe de variables partagées par un
ensemble limité de fonctions (transmet l’adresse d’un struct
aux fonctions)
• permet la construction de structures complexes (listes, arbres,
etc)
Dangers :
• pas/peu de protection contre les pointeurs mal (pas?) initialisés
• risque de corruption des données
Classes de Stockage
int calls;
void f1(int x)
{ nom classe portée durée
static int ctr=0;
int* iptr=NULL; calls globale prg prg
ctr++; x paramètre fct fct
if (x>0) { ctr statique blc prg
int y=x+1;
calls=calls+y;
y locale bloc bloc
} *iptr dynamique – →free
iptr=malloc(sizeof(int));
}
.text .data heap stack
f1( ), main( ) calls, ctr *iptr x, y, iptr
7
Variables Dynamiques
malloc() et free() permettent d’obtenir de nouveaux blocs de
mémoire pour implémenter des variables dynamiques (cf opérateurs
new et dispose du Pascal). Ces variables ne sont utilisables que
par l’intermédiaire de pointeurs.
utilité ?
pour des variables :
• dont la taille ne peut être déterminée qu’à l’exécution
• dont la durée de vie dépend du ’scénario’ d’exécution
dangers
• la mémoire doit être libérée manuellement
• bugs à retardement si libération d’une “mauvaise” adresse
• risque d’utiliser un pointeur vers une variable libérée
10
Petit exemple: listes liées simples
Contruire une List vide
List=NULL;
Ajouter X en tête de List
X->next=List; List=X;
Trouver une entrée dans la List
for (X=List; X && !good(X); X=X->next);
Retirer X de la List
for (Y=List, Prev=NULL; Y && Y!=X; Y=Y->next) Prev=Y;
if (Y==X) {
if (Prev) Prev->next=Y->next;
else List=Y->next;
}
9
Les Bons Trucs de Tonton Pype
La mémoire sans désespoir
• Evitez les malloc quant c’est possible (char msg[x+y+12])
• setenv MALLOC CHECK 2
• Construisez peu de shm, si possible, shmat avant fork
Evitez les deadlocks
• une communication à travers un PIPE ?
• PTHREAD ERRORCHECK MUTEX pour les irréductibles
Surveillez votre programme
• minidebug.h → qui fait quoi
• segv.c → qui plante où
• strace → tous les appels système à la loupe
• assert(x) → ai-je raison
12
Programmation Réseaux Unix
Pourquoi de la programmation parallèle ?
• plusieurs clients → plusieurs opérations concurrentes
• certaines opérations bloquantes → difficile d’assurer de bons
temps de réponse
Comment procéder ?
• fork() permet de construire un clone du processus courant
• le processus-clone hérite des fichiers, socket de son ’père’
• le clone travaille dans une copie de l’espace-mémoire du père.
Comment les faire communiquer ?
• pipe() et socketpair() pour construire des lignes de
communications entre processus
• signal() et kill() pour envoyer des signaux de contrôle.
• fichiers (attention aux accès concurrents).
11