[gull] socket en C

Leopoldo Ghielmetti leopoldo.ghielmetti at a3.epfl.ch
Wed May 14 17:06:41 CEST 2008


Il giorno mer, 14/05/2008 alle 16.42 +0200, Marc Mongenet ha scritto:
> Le 14 mai 2008 15:32, Yann Sagon <ypublic at hasa.ch> a écrit :
> > Bonjour,
> >
> > Je suis en train d'utiliser des socket (af_inet, sock_stream) en C et j'ai
> > quelques questions:
> >
> > comment détecter la perte de connexion d'un client? Dans mon cas, je suis en
> > attente sur un "select" en surveillant un set "readfds". Normalement, le
> > client quite en envoyant une commande, mais dans le cas d'une déconnexion
> > brutale, comment terminer proprement? Faut-il voir du côté d'un timeout?
> 
> Tant qu'on n'utilise pas la connexion, on ne le détecte pas.

Exact, par contre au premier write on le détecte immédiatement, dans ce
cas un beau shutdown et un close s'imposent.
Si le client ferme proprement par contre on reçoit un signal et la
commande read read va retourner 0 bytes lues.

> Dans le livre "UNIX(R) Network Programming Volume 1, Third Edition: The Sockets
> Networking API" il y a un chapitre consacré au crash du serveur, mais je ne vois
> rien pour le crash d'un client. Je suppose que conceptuellement, le serveur n'a
> pas à s'occuper de l'état du client. Le timeout me semble effectivement être
> un moyen le plus propre : c'est-à-dire que conceptuellement, le serveur sert un
> certain temps et pas plus.

Ça dépend du type de serveur et de quel type de client il sert.

> Une autre solution est d'utiliser l'option SO_KEEPALIVE, qui vérifie l'état de
> la connexion toutes les deux heures selon le livre. Mais le livre conseille
> plutôt d'utiliser un timeout dans l'application car SO_KEEPALIVE manque
> de flexibilité.

Oui, le SO_KEEPALIVE est un paramètre global au système qu'a priori il
ne faut pas modifier car sinon on risque des effets de bord sur les
autres applications réseau. L'activer c'est toujours une bonne chose
pour détecter les pertes de connexion, mais malheureusement il est fixé
à 2h.

Ce que moi j'ai fait dans une application que j'avais développé il y a 8
ans c'est d'envoyer un ping applicatif vers le client. Si la connexion
tombe, on le détecte au ping suivant. Si la connexion reste active mais
le client est mort, on le détecte car il ne répond pas.
Ceci implique que le client doit gérer un ping!

> > J'ai également le problème suivant: si un client tente de se connecter sur
> > ma socket et que j'ai atteint le nombre maximale de client, j'aimerais
> > notifier le client. Y a t'il un moyen sans faire de "accept" préalablement?
> > Et également, comment refuser ce client?
> 
> Pas à ma connaissance. Mais si tu veux notifier le client, logiquement il
> faut bien commencer par accepter la connexion, non ?

Exact. Il faut faire un accept et traiter la connexion. La boucle qui
fait les accept doit toujours tourner, simplement si le nombre maximum
de connexion autorisées est atteint, la boucle peut envoyer un message
et déconnecter juste après.
Regarde aussi du côté du nombre de client en attente sur le socket (je
ne me rappelle plus comment s'appelle le paramètre, mais ça à a voir
avec un paramètre listener ou qqc. comme ça), ça permet de dire au
système combien de clients peuvent être en attente de connexion avant
que le système lui même commence à les refuser brutalement.

Faudra aussi tailler les buffers associés aux sockets pour que les
buffers du socket serveur ne soit pas trop gros, tandis que les buffers
des sockets clients ont la bonne taille.

Fais aussi très attention aux paquets "fragmentes" lors-ce que tu traite
tes read/write sur le socket, ne fais jamais de suppositions sur les
données envoyés ou reçues, même si c'est ton code qui les envoie, il est
toujours possible que tu fais un write("toto\n") et que de l'autre côté
tu reçois un "to" et une seconde après "to\n", ou que tu fais
write("toto\n"); sleep(1000);write("titi\n") et que tu reçois "toto
\ntiti\n" en un seul coup.
C'est une erreur courante dans les applications qui utilisent les
sockets. Et ceci n'est pas du tout du aux buffers de l'application ou
des sockets, mais d'une combinaison des deux (des deux côtés de la
connexion), de la connexion elle même et du parcours des paquets sur le
net.
Donc, pas de suppositions.
Les paquets par contre sont conservés si tu communiques en UDP (mais la
il y a d'autres problèmes).

ciao, Leo




More information about the gull mailing list