Il y a environ 18 mois, j’ai rédigé un article de blog traitant des modifications apportées au fonctionnement de la fonction `accept` dans la version 17.1 d’OpenVOS. J’avais toutefois omis de préciser que ces modifications ne s’appliquent que si le code de l’application est basé sur POSIX. Pour résumer, avant la version 17.1, STCP ne répondait à une demande de connexion d’un client que si le code de l’application serveur avait appelé la routine `accept`. Si le code n'avait pas appelé accept, la demande de connexion du client était placée dans une file d'attente mais restait sans réponse. Une fois que l'application appelait accept, STCP envoyait une réponse de connexion. Si le client attendait toujours, la connexion était établie à ce moment-là. Si le client avait déjà abandonné, il répondait à la réponse de connexion par une réinitialisation, STCP rejetait la connexion et la routine accept se bloquait (en mode bloquant) pour attendre une autre connexion.
La figure 1 illustre ce scénario ; les lignes de texte alignées à gauche correspondent aux messages d'état de l'application serveur, tandis que les lignes en retrait de `packet_monitor` (légèrement modifiées) reflètent l'activité du client. L'application (acceptTestnoPosix) est lancée et écoute sur le port 12345 ; une fois en mode écoute, elle se met en veille pendant 300 secondes. Le client établit alors une connexion vers le port 12345 en envoyant un segment TCP à ce port avec le drapeau Syn (S) activé. Il effectue trois tentatives avant d'abandonner. Au bout de 300 secondes, l'application se réveille et appelle la fonction accept. La pile STCP répond au client avec un segment TCP dont les indicateurs Syn et Ack (SA) sont activés. Comme le client n'a plus de trace de la connexion, s'il envoie un Reset (R), STCP se bloque à ce stade. Si la socket était en mode non bloquant, accept aurait renvoyé une erreur EAGAIN.
acceptTestnoPosix 12345 Exécution de acceptTestnoPosix 12345 En attente pendant 300 secondes 11:04:45.923 R TCP 164.152.77.50 164.152.77.217 11071 12345 S 11:04:48.925 R TCP 164.152.77.50 164.152.77.217 11071 12345 S 11:04:54.937 R TCP 164.152.77.50 164.152.77.217 11071 12345 S Prêt à accepter une connexion sur le port numéro 12345 11:09:41.852 T TCP 164.152.77.217 164.152.77.50 12345 11071 SA 11:09:41.854 R TCP 164.152.77.50 164.152.77.217 11071 12345 R |
Figure 1 – Accepter les versions antérieures à la 17.1 ou les versions non POSIX postérieures à la 17.1
Si l'application est basée sur POSIX, le fonctionnement est différent (figure 2). STCP répond immédiatement à la demande de connexion (S) en créant une session (SA). Puis, au bout de 300 secondes, l'application se réactive, appelle la fonction `accept` et STCP renvoie le socket accepté.
acceptTestwithPosix 12345 Exécution de acceptTestnoPosix 12345 En attente pendant 300 secondes 10:58:43.962 R TCP 164.152.77.50 164.152.77.217 11024 12345 S 10:58:43.964 T TCP 164.152.77.217 164.152.77.50 12345 11024 SA 10:58:43.964 R TCP 164.152.77.50 164.152.77.217 11024 12345 A Prêt à accepter une connexion sur le port 12345 Connexion acceptée |
Figure 2 – Acceptation des messages basés sur POSIX 17.1
Cette différence de comportement peut s'avérer cruciale. Si le client attend une réponse de l'application serveur après avoir établi une connexion, il risque de déclencher un délai d'expiration et de fermer la connexion avant même que l'application n'appelle la fonction `accept`.
Comment créer une application avec POSIX ? Tout d'abord, la ligne
#define _POSIX_C_SOURCE 200112L |
doit figurer en première ligne du code source de l'application. Ensuite, le chemin d'accès à la bibliothèque
(master_disk)>système>bibliothèque d'objets POSIX
doit figurer dans les chemins d'accès à la bibliothèque d'objets, après les bibliothèques STCP et avant la bibliothèque C.
Comment savoir si cela a été fait ? Eh bien, vous pouvez consulter les bibliothèques d'objets auxquelles l'application a été liée à l'aide de la commande `display_program_module -object_dirs`.
display_program_module acceptTestwithPosix -object_dirs
%azvos#m17_mas>SysAdmin>Noah_Davids>temp>acceptTestwithPosix.pm
Carte des répertoires d'objets :
11 répertoires de recherche
0 répertoires hors recherche
11 répertoires au total
DTC Chemin d'accès au répertoire
1 %azvos#m17_mas>SysAdmin>Noah_Davids>temp
2 %azvos#m17_mas>system>stcp>object_library
3 %azvos#m17_mas>system>stcp>object_library>socket
4 %azvos#m17_mas>system>stcp>object_library>net
5 %azvos#m17_mas>system>stcp>object_library>common
6 %azvos#m17_mas>system>posix_object_library
7 %azvos#m17_mas>system>c_object_library
8 %azvos#m17_mas>system>object_library
9 %azvos#m17_mas>opt>apache>lib
10 %azvos#m17_mas>opt>openssl>lib
11 %azvos#m17_mas>opt>mysql>lib>mysql
|
Mais cela ne permet pas de savoir si la directive #define fait partie du code source.
Si vous pouvez exécuter le code, vous pouvez vérifier les indicateurs de socket : un programme basé sur POSIX aura l'indicateur de socket SF_POSIX activé. Par exemple, j'ai trois programmes : acceptTestnoPosix, acceptTestwithPosix et acceptTestwithPosixPathOnly. Ce dernier avait le répertoire >system>posix_object_library dans les chemins d'accès aux bibliothèques, mais n'incluait pas la directive #define dans le code source. Notez qu'il s'agit là d'une combinaison non valide. Seule l'application liée à la bibliothèque POSIX et comportant la directive #define POSIX_SOURCE dans son code a créé une socket avec le drapeau SF_POSIX.
acceptTestnoPosix.pm 12345
Exécution de acceptTestnoPosix 12345
Mise en veille pendant 300 secondes
comme suit : match posix ; dump_stcbq -full -lport 12345
comme suit :
|
acceptTestwithPosix.pm 12345
Exécution de acceptTestnoPosix 12345
Mise en veille pendant 300 secondes
comme suit : match posix ; dump_stcbq -full -lport 12345
SF_POSIX
comme :
|
acceptTestwithPosixPathOnly.pm 12345
Exécution de acceptTestnoPosix 12345
Mise en attente pendant 300 secondes
comme suit : match posix ; dump_stcbq -full -lport 12345
comme suit :
|
Il existe une quatrième possibilité : la directive #define a été incluse dans le code source, mais la bibliothèque posix_object_library n'a pas été utilisée. Dans ce cas, la routine de socket renverra une erreur.
acceptTestwithPosixDefineOnly 12345 Exécution de acceptTestnoPosix 12345 acceptTestnoPosix : impossible de créer le socket d'écoute : l'application a été compilée + de manière incorrecte : le runtime POSIX doit être recherché avant le runtime C. |
Toutes les commandes et tous les utilitaires STCP sont développés selon les normes POSIX, et je recommande vivement que les applications que vous développez respectent également ces normes.
