Page suivante Page précédente Table des matières
Le Linux Serial Programming HOWTO
par Peter H. Baumann,
v1.0, 22 janvier 1998mailto:Peter.Bauman= n@dlr.de" NAME=3D"Peter.Baumann@dlr.de">
Adaptation fran=E7aise Etienne BERNARDmailto:eb@via.ec= p.fr" NAME=3D"eb@via.ecp.fr">
Ce document d=E9crit comment programmer sous Linux la communication avec de= s p=E9riph=E9riques sur port s=E9rie.
=20
1. Introduction
- 1.1 Copyright
- 1.2 Nouvelles versions de ce document.
- 1.3 Commentaires
2. D=E9marrage
-- dans le r=E9pertoire des= exemples) pour transmettre des caract=E8res =E0 votre machine Linux.M= initermest tr=E8s simple =E0 compiler et transmettra toute entr=E9e clavi= er directement sur le port s=E9rie. Vous n'= avez qu'=E0 adapter la commande#define MODEMDEVICE "/dev/ttyS0"= =E0 vos besoins. MettezttyS0pour COM1,ttyS1for COM2, = etc... Il est essentiel, pour les tests, que tous les caract=E8res soi= ent transmis bruts (sans traitements= ) au travers de la ligne s=E9rie. Pour tester votre connexion, d=E9marrez <= TT/miniterm/ sur les deux ordinateurs et taper au clavier. Les caract=E8res= =E9crit sur un ordinateur devraient appara=EEtre sur l'autre ordinateur, e= t vice versa. L'entr=E9e clavier sera =E9ga= lement recopi=E9e sur l'=E9cran de l'ordinateur local.Pour fabriquer un c=E2ble null-modem, pour devez croiser les lignes TxD (M/transmit/) et RxD (receive). Pour une description du c=E2ble, r=E9f= =E9rez vous =E0 la section 7 du Serial-HOWTO.
Il est =E9galement possible de faire cet essai avec uniquement un seul ordi= nateur, si vous disposez de deux ports s=E9rie. Vous pouvez lancez deux
/miniterm/s sur deux consoles virtuelles. Si vous lib=E9rez un port s=E9rie= en d=E9connectant la souris, n'oubliez= pas de rediriger/dev/mousesi ce fichier existe. Si vous utilise= z une carte s=E9rie =E0 ports multiples, soyez s=FBr de la configurer corre= ctement. La mienne n'=E9tait pas correctement configur=E9e, et tout fonctio= nnait correctement lorsque je testais s= ur mon ordinateur. Lorsque je l'ai connect=E9 =E0 un autre, le port a comme= nc=E9 =E0 perdre des caract=E8res. L'ex=E9cution de deux programmes sur un = seul ordinateur n'est pas totalement asynchrone.- 2.2 Configuration des ports
2.2 Configuration des ports
Les p=E9riph=E9riques
/dev/ttyS*sont destin=E9s =E0 connecter les= terminaux =E0 votre machine Linux, et sont configur=E9s pour cet usage apr= =E8s le d=E9marrage. Vous devez vous en souvenir lorsque vous programmez la= communication avec un p=E9riph=E9rique autre. Pa= r exemple, les ports sont configur=E9s pour afficher les caract=E8res envoy= =E9s vers lui-m=EAme, ce qui normalement doit =EAtre chang=E9 pour la trans= mission de donn=E9es.Tous les param=E8tres peuvent =EAtre facilement configur=E9 depuis un progr= amme. La configuration est stock=E9e dans une structure de type
struct = termios, qui est d=E9finie dans<asm/termbits.h>:#define NCCS 19 struct termios { tcflag_t c_iflag; /* Modes d'entr=E9e */ tcflag_t c_oflag; /* Modes de sortie */ tcflag_t c_cflag; /* Modes de contr=F4le */ tcflag_t c_lflag; /* Modes locaux */ cc_t c_line; /* Discipline de ligne */ cc_t c_cc[NCCS]; /* Caract=E8res de contr=F4le */ };Ce fichier inclus =E9galement la d=E9finition des constantes. Tous les mode= s d'entr=E9e dans
c_iflagprennent en charge le traitement de l'en= tr=E9e, ce qui signifie que les caract=E8res envoy=E9s depuis le p=E9riph= =E9rique peuvent =EAtre trait=E9s avant d'=EAtre lu p= arread. De la m=EAme fa=E7on,c_oflagsse chargent du tr= aitement en sortie.c_cflagcontient les param=E8tres du port, com= me la vitesse, le nombre de bits par caract=E8re, les bits d'arr=EAt, etc..= . Les modes locaux, stock=E9s dansc_= lflagd=E9terminent si les caract=E8res sont imprim=E9s, si des signau= x sont envoy=E9s =E0 votre programme, etc... Enfin, le tableauc_cc> d=E9finit les caract=E8res de contr=F4le pour la fin de fichier, le carac= t=E8re stop, etc... Les valeurs par d=E9faut pour= les caract=E8res de contr=F4le sont d=E9finies dans<asm/termios.h&= gt;. Les modes possibles sont d=E9crits dans la page de manuel de= termios(3). La structuretermioscontient un champc_line=(discipline de ligne), qui n'es= t pas utilis=E9 sur les syst=E8mes conformes =E0 POSIX.
- 2.3 Fa=E7ons de lire sur les p=E9riph=E9riques s=E9rie
2.3 Fa=E7ons de lire sur les p=E9riph=E9riques s=E9rie
Voici trois fa=E7ons de lire sur les p=E9riph=E9riques s=E9rie. Le moyen ap= propri=E9 doit =EAtre choisi pour chaque application. Lorsque cela est poss= ible, ne lisez pas les cha=EEnes caract=E8re par caract=E8re. Lorsque j'uti= lisais ce moyen, je perdais des caract=E8res, alo= rs qu'un
readsur la cha=EEne compl=E8te ne donnait aucune erreur.
Entr=E9e canonique
C'est le mode de fonctionnement normal pour les terminaux, mais peut =E9gal= ement =EAtre utilis=E9 pour communiquer avec d'autres p=E9riph=E9riques. To= utes les entr=E9es sont trait=E9es lignes par lignes, ce qui signifie qu'un=
readne renverra qu'une ligne com= pl=E8te. Une ligne est termin=E9e par d=E9faut avec un caract=E8reNL</= TT> (ACIIsera bloquant, jusqu'=E0 ce que la lecture soit satisfaite. En= mode asynchrone, un appel =E0LF), une fin de fichier, ou un caract=E8re de fin de lig= ne. UnCR(le caract=E8re de fin de ligne par d=E9faut de DOS et W= indows) ne terminera pas une ligne, avec le= s param=E8tres par d=E9faut.L'entr=E9e canonique peut =E9galement prendre en charge le caract=E8re eras= e, d'effacement de mot, et de r=E9affichage, la traduction de
CRv= ersNL, etc...
Entr=E9e non canonique
L'entr=E9e non canonique va prendre en charge un nombre fix=E9 de caract=E8= re par lecture, et autorise l'utilisation d'un compteur de temps pour les c= aract=E8res. Ce mode doit =EAtre utilis=E9 si votre application lira toujou= rs un nombre fix=E9 de caract=E8res, ou si le= p=E9riph=E9rique connect=E9 envoit les caract=E8res par paquet.
Entr=E9e asynchrone
Les deux modes ci-dessus peut =EAtre utilis=E9 en mode synchrone ou asynchr= one. Le mode synchrone est le mode par d=E9faut, pour lequel un appel =E0 <= TT>read
read</= TT> retournera imm=E9diatement et lancera un signal au programme appelant e= n fin de transfert. Ce signal peut =EAtre re=E7u par un gestionnaire de sig= nal.).Attente d'entr=E9e depuis de multiples sources
Cela ne constitue pas un mode d'entr=E9e diff=E9rent, mais peut s'av=E9rer = =EAtre utile, si vous prenez en charge des p=E9riph=E9riques multiples. Dan= s mon application, je traitais l'entr=E9e depuis une socket TCP/IP et depui= s une connexion s=E9rie sur un autre ordinate= ur quasiment en m=EAme temps. L'exemple de programme donn=E9 plus loin atte= ndra des caract=E8res en entr=E9e depuis deux sources. Si des donn=E9es sur= l'une des sources deviennent disponibles, elles seront trait=E9es, et le p= rogramme attendra de nouvelles donn=E9es.
L'approche pr=E9sent=E9e plus loin semble plut=F4t complexe, mais il est im= portant que vous vous rappeliez que Linux est un syst=E8me multi-t=E2che. L= 'appel syst=E8me
selectne charge pas le processeur lorsqu'il atte= nd des donn=E9es, alors que le fait de fair= e une boucle jusqu'=E0 ce que des caract=E8res deviennent disponibles ralen= tirait les autres processus.
3. Exemples de programmes
R=E9f=E9rez-vous aux commentaires dans le code source pour l'explication de= s diff=E9rents modes d'entr=E9e. J'esp=E8re que le code est compr=E9hensibl= e. L'exemple sur l'entr=E9e canonique est la plus comment=E9e, les autres e= xemples sont comment=E9s uniquement lorsqu'ils=20= diff=E8rent, afin de signaler les diff=E9rences.
Les descriptions ne sont pas compl=E8tes, mais je vous encourage =E0 modifi= er les exemples pour obtenir la solution la plus int=E9ressante pour votre = application.
N'oubliez pas de donner les droits corrects aux ports s=E9rie (par exemple,=
chmod a+rw /dev/ttyS1) !
- 3.1 Traitement canonique
3.1 Traitement canonique
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> /* les valeurs pour la vitesse, baudrate, sont d=E9finies dans <asm/termbit= s.h>, qui est inclus dans <termios.h> */ #define BAUDRATE B38400 =20 /* changez cette d=E9finition pour utiliser le port correct */ #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* code source conforme =E0 POSIX */ #define FALSE 0 #define TRUE 1 volatile int STOP=3DFALSE;=20 main() { int fd,c, res; struct termios oldtio,newtio; char buf[255]; /*=20 On ouvre le p=E9riph=E9rique du modem en lecture/=E9criture, et pas comme terminal de contr=F4le, puisque nous ne voulons pas =EAtre termin=E9 si l= 'on re=E7oit un caract=E8re CTRL-C. */ fd =3D open(MODEMDEVICE, O_RDWR | O_NOCTTY );=20 if (fd <0) {perror(MODEMDEVICE); exit(-1); } tcgetattr(fd,&oldtio); /* sauvegarde de la configuration courante */ bzero(&newtio, sizeof(newtio)); /* on initialise la structure =E0 z=E9= ro */ /*=20 BAUDRATE: Affecte la vitesse. vous pouvez =E9galement utiliser cfsetispeed et cfsetospeed. CRTSCTS : contr=F4le de flux mat=E9riel (uniquement utilis=E9 si le c=E2b= le a les lignes n=E9cessaires. Voir la section 7 du Serial-HOWTO). CS8 : 8n1 (8 bits,sans parit=E9, 1 bit d'arr=EAt) CLOCAL : connexion locale, pas de contr=F4le par le modem CREAD : permet la r=E9ception des caract=E8res */ newtio.c_cflag =3D BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; =20 /* IGNPAR : ignore les octets ayant une erreur de parit=E9. ICRNL : transforme CR en NL (sinon un CR de l'autre c=F4t=E9 de la ligne ne terminera pas l'entr=E9e). sinon, utiliser l'entr=E9e sans traitement (device en mode raw). */ newtio.c_iflag =3D IGNPAR | ICRNL; =20 /* Sortie sans traitement (raw). */ newtio.c_oflag =3D 0; =20 /* ICANON : active l'entr=E9e en mode canonique d=E9sactive toute fonctionnalit=E9 d'echo, et n'envoit pas de signal au programme appelant. */ newtio.c_lflag =3D ICANON; =20 /*=20 initialise les caract=E8res de contr=F4le. les valeurs par d=E9faut peuvent =EAtre trouv=E9es dans /usr/include/termios.h, et sont donn=E9es dans les commentaires. Elles sont inutiles ici. */ newtio.c_cc[VINTR] =3D 0; /* Ctrl-c */=20 newtio.c_cc[VQUIT] =3D 0; /* Ctrl-\ */ newtio.c_cc[VERASE] =3D 0; /* del */ newtio.c_cc[VKILL] =3D 0; /* @ */ newtio.c_cc[VEOF] =3D 4; /* Ctrl-d */ newtio.c_cc[VTIME] =3D 0; /* compteur inter-caract=E8re non utilis= =E9 */ newtio.c_cc[VMIN] =3D 1; /* read bloquant jusqu'=E0 l'arriv=E9e d'= 1 caract=E8re */ newtio.c_cc[VSWTC] =3D 0; /* '\0' */ newtio.c_cc[VSTART] =3D 0; /* Ctrl-q */=20 newtio.c_cc[VSTOP] =3D 0; /* Ctrl-s */ newtio.c_cc[VSUSP] =3D 0; /* Ctrl-z */ newtio.c_cc[VEOL] =3D 0; /* '\0' */ newtio.c_cc[VREPRINT] =3D 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] =3D 0; /* Ctrl-u */ newtio.c_cc[VWERASE] =3D 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] =3D 0; /* Ctrl-v */ newtio.c_cc[VEOL2] =3D 0; /* '\0' */ /*=20 =E0 pr=E9sent, on vide la ligne du modem, et on active la configuration pour le port */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); /* la configuration du terminal est faite, =E0 pr=E9sent on traite les entr=E9es Dans cet exemple, la r=E9ception d'un 'z' en d=E9but de ligne mettra fin au programme. */ while (STOP=3D=3DFALSE) { /* boucle jusqu'=E0 condition de terminaison= */ /* read bloque l'ex=E9cution du programme jusqu'=E0 ce qu'un caract=E8re de fin de ligne soit lu, m=EAme si plus de 255 caract=E8res sont saisis. Si le nombre de caract=E8res lus est inf=E9rieur au nombre de caract=E8= res disponibles, des read suivant retourneront les caract=E8res restants. res sera positionn=E9 au nombre de caract=E8res effectivement lus */ res =3D read(fd,buf,255);=20 buf[res]=3D0; /* on termine la ligne, pour pouvoir l'afficher */ printf(":%s:%d\n", buf, res); if (buf[0]=3D=3D'z') STOP=3DTRUE; } /* restaure les anciens param=E8tres du port */ tcsetattr(fd,TCSANOW,&oldtio); }
- 3.2 Entr=E9e non canonique
3.2 Entr=E9e non canonique
Dans le mode non canonique, les caract=E8res lus ne sont pas assembl=E9s li= gne par ligne, et ils ne subissent pas de traitement (erase, kill, delete, = etc...). Deux param=E8tres contr=F4lent ce mode :
c_cc[VTIME]= positionne le timer de caract=E8r= es, etc_cc[VMIN]indique le nombre minimum de caract=E8res =E0 re= cevoir avant qu'une lecture soit satisfaite.Si MIN > 0 et TIME =3D 0, MIN indique le nombre de caract=E8res =E0 rece= voir avant que la lecture soit satisfaite. TIME est =E9gal =E0 z=E9ro, et l= e timer n'est pas utilis=E9.
Si MIN =3D 0 et TIME > 0, TIME est utilis=E9 comme une valeur de ti= meout. Une lecture est satisfaite lorsqu'un caract=E8re est re=E7u, ou que= la dur=E9e TIME est d=E9pass=E9e (t =3D TIME * 0.1s). Si TIME est d=E9pass= =E9, aucun caract=E8re n'est retourn=E9.
Si MIN > 0 et TIME > 0, TIME est employ=E9 comme timer entre cha= que caract=E8re. La lecture sera satisfaite si MIN caract=E8res sont re=E7u= s, ou que le timer entre deux caract=E8res d=E9passe TIME. Le time= r est r=E9initialis=E9 =E0 chaque fois qu'un c= aract=E8re est re=E7u, et n'est activ=E9 qu'apr=E8s la r=E9ception du premi= er caract=E8re.
Si MIN =3D 0 et TIME =3D 0, le retour est imm=E9diat. Le nombre de caract= =E8res disponibles, ou bien le nombre de caract=E8res demand=E9 est retourn= =E9. Selon Antonino (voir le paragraphe sur les participations), vous pouve= z utiliser un
fcntl(fd, F_SETFL, FNDELAY)= ;avant la lecture pour obtenir le m=EAme r=E9sultat.Vous pouvez tester tous les modes d=E9crit ci-dessus en modifiant
newti= o.c_cc[VTIME]etnewtio.c_cc[VMIN].
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* code source conforme =E0 POSIX */ #define FALSE 0 #define TRUE 1 volatile int STOP=3DFALSE;=20 main() { int fd,c, res; struct termios oldtio,newtio; char buf[255]; fd =3D open(MODEMDEVICE, O_RDWR | O_NOCTTY );=20 if (fd <0) {perror(MODEMDEVICE); exit(-1); } tcgetattr(fd,&oldtio); /* sauvegarde de la configuration courante */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag =3D BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag =3D IGNPAR; newtio.c_oflag =3D 0; /* positionne le mode de lecture (non canonique, sans echo, ...) */ newtio.c_lflag =3D 0; =20 newtio.c_cc[VTIME] =3D 0; /* timer inter-caract=E8res non utilis=E9 */ newtio.c_cc[VMIN] =3D 5; /* read bloquant jusqu'=E0 ce que 5 */ /* caract=E8res soient lus */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); while (STOP=3D=3DFALSE) { /* boucle de lecture */ res =3D read(fd,buf,255); /* retourne apr=E8s lecture 5 caract=E8res */ buf[res]=3D0; /* pour pouvoir les imprimer... */ printf(":%s:%d\n", buf, res); if (buf[0]=3D=3D'z') STOP=3DTRUE; } tcsetattr(fd,TCSANOW,&oldtio); }
- 3.3 Lecture asynchrone
3.3 Lecture asynchrone
#include <termios.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/signal.h> #include <sys/types.h> #define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyS1" #define _POSIX_SOURCE 1 /* code source conforme =E0 POSIX */ #define FALSE 0 #define TRUE 1 volatile int STOP=3DFALSE;=20 void signal_handler_IO (int status); /* le gestionnaire de signal */ int wait_flag=3DTRUE; /* TRUE tant que re=E7u aucun signal */ main() { int fd,c, res; struct termios oldtio,newtio; struct sigaction saio; /* d=E9finition de l'action du signal */ char buf[255]; /* ouvre le port en mon non-bloquant (read retourne imm=E9diatement) */ fd =3D open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd <0) {perror(MODEMDEVICE); exit(-1); } /* installe le gestionnaire de signal avant de passer le port en mode asynchrone */ saio.sa_handler =3D signal_handler_IO; saio.sa_mask =3D 0; saio.sa_flags =3D 0; saio.sa_restorer =3D NULL; sigaction(SIGIO,&saio,NULL); =20 /* permet au processus de recevoir un SIGIO */ fcntl(fd, F_SETOWN, getpid()); /* rend le descripteur de fichier asynchrone (la page de manuel indique que seuls O_APPEND et O_NONBLOCK fonctionnent avec F_SETFL...) */ fcntl(fd, F_SETFL, FASYNC); tcgetattr(fd,&oldtio); /* sauvegarde de la configuration courante */ /* positionne les nouvelles valeurs pour lecture canonique */ newtio.c_cflag =3D BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag =3D IGNPAR | ICRNL; newtio.c_oflag =3D 0; newtio.c_lflag =3D ICANON; newtio.c_cc[VMIN]=3D1; newtio.c_cc[VTIME]=3D0; tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); =20 /* on boucle en attente de lecture. g=E9n=E9ralement, on r=E9alise des traitements =E0 l'int=E9rieur de la boucle */ while (STOP=3D=3DFALSE) { printf(".\n");usleep(100000); /* wait_flag =3D FALSE apr=E8s r=E9ception de SIGIO. Des donn=E9es sont disponibles et peuvent =EAtre lues */ if (wait_flag=3D=3DFALSE) {=20 res =3D read(fd,buf,255); buf[res]=3D0; printf(":%s:%d\n", buf, res); if (res=3D=3D1) STOP=3DTRUE; /* on arr=EAte la boucle si on lit une ligne seule */ wait_flag =3D TRUE; /* on attend de nouvelles donn=E9es */ } } /* restaure les anciens param=E8tres du port */ tcsetattr(fd,TCSANOW,&oldtio); } /*************************************************************************** * gestionnaire de signal. Positionne wait_flag =E0 FALSE, pour indiquer =E0= * * la boucle ci-dessus que des caract=E8res ont =E9t=E9 re=E7us. = * ***************************************************************************/ void signal_handler_IO (int status) { printf("r=E9ception du signal SIGIO.\n); wait_flag =3D FALSE; }
- 3.4 Multiplexage en lecture
3.4 Multiplexage en lecture
Cette section est r=E9duite au minimum, et n'est l=E0 que pour vous guider.= Le code source d'exemple pr=E9sent=E9 est donc r=E9duit au strict minimum.= Il ne fonctionnera pas seulement avec des ports s=E9rie, mais avec n'impor= te quel ensemble de descripteurs de fichi= ers.
L'appel syst=E8me select et les macros qui lui sont attach=E9es utilisent u= n
fd_set. C'est un tableau de bits, qui dispose d'un bit pour chaq= ue descripteur de fichier valide.selectaccepte unfd_setayant = les bits positionn=E9s pour les des= cripteurs de fichiers qui conviennent, et retourne unfd_set, dans leq= uel les bits des descripteurs de fichier o=F9 une lecture, une =E9criture o= u une exception sont positionn=E9s. Toutes les manipulations defd_set<= /TT> sont faites avec les macros fo= urnies. Reportez vous =E9galement =E0 la page de manuel deselect(2) T>.#include <sys/time.h> #include <sys/types.h> #include <unistd.h> main() { int fd1, fd2; /* entr=E9es 1 et 2 */ fd_set readfs; /* ensemble de descripteurs */ int maxfd; /* nombre max des descripteurs utilis=E9s */ int loop=3D1; /* boucle tant que TRUE */ /* open_input_source ouvre un p=E9riph=E9rique, configure le port correctement, et retourne un descripteur de fichier. */ fd1 =3D open_input_source("/dev/ttyS1"); /* COM2 */ if (fd1<0) exit(0); fd2 =3D open_input_source("/dev/ttyS2"); /* COM3 */ if (fd2<0) exit(0); maxfd =3D MAX (fd1, fd2)+1; /* num=E9ro maximum du bit =E0 tester */ /* boucle d'entr=E9e */ while (loop) { FD_SET(fd1, &readfs); /* test pour la source 1 */ FD_SET(fd2, &readfs); /* test pour la source 2 */ /* on bloque jusqu'=E0 ce que des caract=E8res soient disponibles en lecture */ select(maxfd, &readfs, NULL, NULL, NULL); if (FD_ISSET(fd1)) /* caract=E8res sur 1 */ handle_input_from_source1(); if (FD_ISSET(fd2)) /* caract=E8res sur 2 */ handle_input_from_source2(); } } =20L'exemple ci-dessus bloque ind=E9finiment, jusqu'=E0 ce que des caract=E8re= s venant d'une des sources soient disponibles. Si vous avez besoin d'un /timeout/, remplacez juste l'appel =E0 select par :
int res; struct timeval Timeout; /* fixe la valeur du timeout */ Timeout.tv_usec =3D 0; /* millisecondes */ Timeout.tv_sec =3D 1; /* secondes */ res =3D select(maxfd, &readfs, NULL, NULL, &Timeout); if (res=3D=3D0) /* nombre de descripteurs de fichiers avec caract=E8res disponibles =3D 0, il y a eu timeout */Cet exemple verra l'expiration du delai de timeout apr=E8s une seconde= . S'il y a timeout, select retournera 0, mais fa=EEtes attention,
= Timeoutest d=E9cr=E9ment=E9 du temps r=E9ellement attendu parsel= ect. Si la valeur de timeout est 0,= select retournera imm=E9diatement.
4. Autres sources d'information
5. Contributions
Page suivante Page précédente Table des matières