0% ont trouvé ce document utile (0 vote)
63 vues6 pages

0276 Programmation C Sockets

Transféré par

Mackus Da Silva
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • protocole Internet,
  • réseaux IPv4,
  • tests de réseau,
  • fonction sendto,
  • système d'exploitation,
  • sockets,
  • communication réseau,
  • messages traités,
  • fonction recv,
  • communication orientée connexi…
0% ont trouvé ce document utile (0 vote)
63 vues6 pages

0276 Programmation C Sockets

Transféré par

Mackus Da Silva
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • protocole Internet,
  • réseaux IPv4,
  • tests de réseau,
  • fonction sendto,
  • système d'exploitation,
  • sockets,
  • communication réseau,
  • messages traités,
  • fonction recv,
  • communication orientée connexi…

Initiation au développement C sur les sockets

Philippe Latu
philippe.latu(at)inetdoc.net
http://www.inetdoc.net

L'objet de ce support est d'initier au développement réseau sur les sockets à partir du
code le plus minimaliste et le plus portable. Dans ce but, on utilise les fonctions réseau des
bibliothèques standard du Langage C et on se limite à l'utilisation d'adresses IPv4 en couche
réseau.

Table des matières


1. Copyright et Licence ........................................................................................................................... 1
1.1. Meta-information ...................................................................................................................... 1
2. Contexte de développement ................................................................................................................. 2
2.1. Système d'exploitation .............................................................................................................. 2
2.2. Instructions de compilation ....................................................................................................... 2
2.3. Instructions d'exécution ............................................................................................................ 2
2.4. Bibliothèques utilisées .............................................................................................................. 3
2.5. Choix du premier protocole de transport étudié ........................................................................ 4
2.6. Sockets & protocole de transport UDP ..................................................................................... 4
2.7. Sockets & protocole de transport TCP ...................................................................................... 4
3. Programme client UDP ........................................................................................................................ 5
3.1. Utilisation des sockets avec le client UDP ................................................................................ 5
3.2. Code source complet ................................................................................................................ 6
4. Programme serveur UDP ..................................................................................................................... 7
4.1. Utilisation des sockets avec le serveur UDP ............................................................................. 7
4.2. Code source complet ................................................................................................................ 8
5. Programme client TCP ......................................................................................................................... 9
5.1. Utilisation des sockets avec le client TCP ................................................................................. 9
5.2. Patch code source .................................................................................................................... 9
6. Programme serveur TCP .................................................................................................................... 10
6.1. Utilisation des sockets avec le serveur TCP ............................................................................ 10
6.2. Patch code source ................................................................................................................... 10
7. Analyse réseau avec Wireshark ......................................................................................................... 11
7.1. Analyse avec le protocole UDP ............................................................................................... 12
7.2. Analyse avec le protocole TCP ................................................................................................ 12
8. Documents de référence .................................................................................................................... 13

1. Copyright et Licence
Copyright (c) 2000,2012 Philippe Latu.
Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.3 or any later version
published by the Free Software Foundation; with no Invariant Sections, no
Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included
in the section entitled "GNU Free Documentation License".

Copyright (c) 2000,2012 Philippe Latu.


Permission est accordée de copier, distribuer et/ou modifier ce document selon
les termes de la Licence de Documentation Libre GNU (GNU Free Documentation
License), version 1.3 ou toute version ultérieure publiée par la Free Software
Foundation ; sans Sections Invariables ; sans Texte de Première de Couverture,
et sans Texte de Quatrième de Couverture. Une copie de la présente Licence est
incluse dans la section intitulée « Licence de Documentation Libre GNU ».

1.1. Meta-information
1 2
Cet article est écrit avec DocBook XML sur un système Debian GNU/Linux . Il est disponible en version
3
imprimable au format PDF : socket-c.pdf .

1
http://www.docbook.org
2
http://www.debian.org
3
http://www.inetdoc.net/pdf/socket-c.pdf

Initiation au développement C sur les sockets 1


Initiation au développement C sur les sockets

2. Contexte de développement
L'objectif de développement étant l'initiation, on se limite à un code minimaliste utilisant deux programmes
distincts : un serveur et un client. Ces deux programmes échangent des chaînes caractères. Le client émet
un message que le serveur traite et retransmet vers le client. Le traitement est tout aussi minimaliste ; il
convertit la chaîne de caractères en majuscules.

2.1. Système d'exploitation


Le schéma ci-dessous permet de faire la correspondance entre les couches de la modélisation contemporaine
et celles de la représentation macroscopique d'un système d'exploitation.

Le logiciel correspondant aux protocoles allant de la couche physique jusqu'à la couche transport fait partie
du sous-système réseau du noyau du système d'exploitation.
Le programme utilisateur est lancé à partir de la couche Shell et est exécuté au niveau application.
L'utilisation de sockets revient à ouvrir un canal de communication entre la couche application et la couche
transport. La programmation des sockets se fait à l'aide de bibliothèques standard présentées ci-après :
Section 2.4, « Bibliothèques utilisées ».

2.2. Instructions de compilation


Il est possible de compiler les deux programmes client et serveur en l'état sur n'importe quel système GNU/
Linux. Il suffit d'appeler le compilateur C de la chaîne de développement GNU en désignant le nom du
programme exécutable avec l'option -o.
$ gcc -Wall -o udp-client.o udp-client.c
$ gcc -Wall -o udp-server.o udp-server.c
$ ls udp*
udp-client.c udp-client.o udp-server.c udp-server.o

2.3. Instructions d'exécution


L'évaluation des deux programmes client et serveur est assez simple. On peut les exécuter sur le même hôte
dans deux Shells distincts en utilisant l'interface de boucle locale pour les communications réseau.

Le programme serveur, udp-server.o


$ ./udp-server.o
Entrez le numéro de port utilisé en écoute (entre 1500 et 65000) :
4500
Attente de requête sur le port 4500
>> depuis 127.0.0.1:39311
Message reçu : texte avec tabulation et espaces

Le programme client, udp-client.o


$ ./udp-client.o
Entrez le nom du serveur ou son adresse IP :
127.0.0.1
Entrez le numéro de port du serveur :
4500

Entrez quelques caractères au clavier.


Le serveur les modifiera et les renverra.
Pour sortir, entrez une ligne avec le caractère '.' uniquement.
Si une ligne dépasse 100 caractères,
seuls les 100 premiers caractères seront utilisés.

Saisie du message :
texte avec tabulation et espaces

Initiation au développement C sur les sockets 2


Initiation au développement C sur les sockets

Message traité : TEXTE AVEC TABULATION ET ESPACES


Saisie du message :
.

Lorsque le programme serveur est en cours d'exécution, il est possible de visualiser la correspondance entre
le processus en cours d'exécution et le numéro de port en écoute à l'aide de la commande netstat.
$ netstat -aup | grep -e Proto -e udp-server
(Tous les processus ne peuvent être identifiés, les infos sur les processus
non possédés ne seront pas affichées, vous devez être root pour les voir toutes.)
Proto Recv-Q Send-Q Adresse locale Adresse distante Etat PID/Program name
udp 0 0 *:4500 *:* 3157/udp-server.o

Dans l'exemple ci-dessus, le numéro de port 4500 apparaît dans la colonne Adresse locale et processus numéro
correspond bien au programme udp-server.o dans la colonne PID/Program name.
3157

2.4. Bibliothèques utilisées


Les deux programmes utilisent les mêmes fonctions disponibles à partir des bibliothèques standards.

libc6-dev, netdb.h
Opérations sur les bases de données réseau. Ici, c'est la fonction gethostbyname() qui est utilisée. Elle
renvoie une structure de type hostent pour l'hôte name. La chaîne name est soit un nom d'hôte, soit une
adresse IPv4, soit une adresse IPv6. Pour obtenir plus d'informations, il faut consulter les pages de
manuels : man gethostbyname.

libc6-dev, netinet/in.h
Famille du protocole Internet. Ici, plusieurs fonctions sont utilisées à partir du paramètre de description
de socket sockaddr_in. Les quatre fonctions importantes traitent de la conversion des nombres représentés
suivant le format hôte (octet le moins significatif en premier sur processeur Intel x86) ou suivant le format
défini dans les en-têtes réseau (octet le plus significatif en premier). Ici le format hôte fait référence à
l'architecture du processeur utilisé. Cette architecture est dite «petit-boutiste» pour les processeurs de
marque Intel™ majoritairement utilisés dans les ordinateurs de type PC. À l'inverse, le format défini dans
les en-têtes réseau est dit «gros-boutiste». Cette définition appelée Network Byte Order provient à la fois
du protocole IP et de la couche liaison du modèle OSI.

• htonl() et htons() : conversion d'un entier long et d'un entier court depuis la représentation hôte (octet
le moins significatif en premier ou Least Significant Byte First) vers la représentation réseau standard
(octet le plus significatif en premier ou Most Significant Byte First).

• ntohl() et ntohs() : fonctions opposées aux précédentes. Conversion de la représentation réseau vers
la représentation hôte.

libstdc++6-dev, stdio.h
Opérations sur les flux d'entrées/sorties de base tels que l'écran et le clavier. Ici, toutes les opérations
de saisie de nom d'hôte, d'adresse IP, de numéro de port ou de texte sont gérées à l'aide des fonctions
usuelles du langage C.
Les fonctions d'affichage sans formatage puts et fputs ainsi que la fonction d'affichage avec formatage
printfsont utilisées de façon classique.
En revanche, la saisie des chaînes de caractères à l'aide de la fonction scanf est plus singulière. Comme le
but des communications réseau évaluées ici est d'échanger des chaînes de caractères, il est nécessaire de
transmettre ou recevoir des suites de caractères comprenant aussi bien des espaces que des tabulations.
La syntaxe usuelle de saisie d'une chaîne de caractère est :
scanf("%s", msg);

Si on se contente de cette syntaxe par défaut, la chaîne saisie est transmise par le programme client mot
par mot. En conséquence, le traitement par le programme serveur est aussi effectué mot par mot.
Pour transmettre une chaîne complète, on utilise une syntaxe du type suivant :
scanf(" %[^\n]%*c", msg);

Le caractère espace situé entre les guillemets de gauche et le signe pourcentage a pour but d'éliminer
les caractères ' ', '\t' et '\n' qui subsisteraient dans la mémoire tampon du flux d'entrée standard stdin
avant la saisie de nouveaux caractères.
La syntaxe [^\n] précise que tous les caractères différents du saut de ligne sont admis dans la saisie. On
évite ainsi que les caractères ' ' et '\t' soient considérés comme délimiteurs.
L'ajout de %*c permet d'éliminer le délimiteur '\n' et tout caractère situé après dans la mémoire tampon
du flux d'entrée standard.
Enfin, pour éviter tout débordement de la mémoire tampon du même flux d'entrée standard, on limite
le nombre maximum des caractères saisis à la quantité de mémoire réservée pour stocker la chaîne
de caractères. La «constante» MAX_MSG définie via une directive de préprocesseur est introduite dans la
syntaxe de formatage de la saisie. Pour cette manipulation, on fait appel à une fonction macro qui renvoie
la valeur de MAX_MSG comme nombre maximum de caractères à saisir.

Initiation au développement C sur les sockets 3


Initiation au développement C sur les sockets

On obtient donc finalement le formatage de la saisie d'une chaîne de caractères suivant :


scanf(" %"xstr(MAX_MSG)"[^\n]%*c", msg);

D'une manière générale, toutes les fonctions sont documentées à l'aide des pages de manuels Unix classiques.
Soit on entre directement à la console une commande du type : man inet_ntoa, soit on utilise l'aide du
gestionnaire graphique pour accéder aux mêmes informations en saisissant une URL du type suivant à partir
du gestionnaire de fichiers : man:/inet_ntoa.

2.5. Choix du premier protocole de transport étudié


Au dessus du protocole de couche réseau IP, on doit choisir entre deux protocoles de couche transport :
TCP ou UDP.
Dans l'ordre chronologique, le protocole TCP est le premier protocole à avoir été développé. Il «porte la
moitié» de la philosophie du modèle Internet. Cette philosophie veut que la couche transport soit le lieu de la
fiabilisation des communications. Ce protocole fonctionne donc en mode connecté et contient tout les outils
nécessaires à l'établissement, au maintien et à la libération de connexion. De plus, des numéros de séquences
garantissent l'intégrité de la transmission et le fenêtrage de ces numéros de séquences assure un contrôle
de flux. Tout ces mécanismes ne sont pas évidents à appréhender pour un public débutant.
Le protocole UDP a été développé après TCP. La philosophie de ce mode de transport suppose que le
réseau de communication est intrinsèquement fiable et qu'il n'est pas nécessaire de garantir l'intégrité des
transmissions et de contrôler les flux. On dit que le protocole UDP n'est pas orienté connexion ; ce qui a pour
conséquence d'alléger considérablement les mécanismes de transport.
L'objectif du présent document étant d'initier à l'utilisation des sockets, on s'appuie dans un premier temps
sur le protocole de transport le plus simple : UDP. Les programmes «client» et «serveur» sont repris dans un
second temps en utilisant le protocole TCP. En termes de développement, les différences de mise en œuvre
des sockets sont minimes. C'est à l'analyse réseau que la différence se fait sachant que les mécanismes de
fonctionnement des deux protocoles sont très différents.
Pour plus d'informations, consulter le support Modélisations réseau.

2.6. Sockets & protocole de transport UDP


Le schéma ci-dessous présente les sous-programmes sélectionnés côté client et côté serveur pour la mise en
œuvre des sockets avec le protocole de transport UDP.
Les appels de sous-programmes avec les passages de paramètres sont détaillés dans les sections suivantes.

• Client : Section 3.1, « Utilisation des sockets avec le client UDP »

• Serveur : Section 4.1, « Utilisation des sockets avec le serveur UDP »

2.7. Sockets & protocole de transport TCP


Le schéma ci-dessous présente les sous-programmes sélectionnés côté client et côté serveur pour la mise en
œuvre des sockets avec le protocole de transport TCP.
Les appels de sous-programmes avec les passages de paramètres sont détaillés dans les sections suivantes.

• Client : Section 5.1, « Utilisation des sockets avec le client TCP »

• Serveur : Section 6.1, « Utilisation des sockets avec le serveur TCP »

Initiation au développement C sur les sockets 4


Initiation au développement C sur les sockets

3. Programme client UDP

3.1. Utilisation des sockets avec le client UDP


Au niveau du client, l'objectif est d'ouvrir un nouveau socket ; ce qui revient à ouvrir un canal de
communication réseau avec la fonction socket.

int socketDescriptor;

<snipped/>
socketDescriptor = socket(PF_INET , SOCK_DGRAM , IPPROTO_UDP );
if (socketDescriptor < 0) {
fputs("Impossible de créer le socket", stderr);
exit(EXIT_FAILURE);
}

PF_INET désigne la famille de protocole de couche réseau IPv4.


SOCK_DGRAM désigne un service de transmission de datagrammes non orienté connexion.
IPPROTO_UDP désigne l'utilisation du protocole UDP au niveau de la couche transport.

Une fois le canal de communication réseau correctement ouvert, on peut passer à l'émission des datagrammes
avec la fonction sendto.

int socketDescriptor;
char msg[MSG_ARRAY_SIZE];
struct sockaddr_in serverAddress;

<snipped/>
if (sendto(socketDescriptor , msg, msgLength , 0,
(struct sockaddr *) &serverAddress,
sizeof(serverAddress) ) < 0) {
fputs("Émission du message impossible", stderr);
close(socketDescriptor);
exit(EXIT_FAILURE);
}

socketDescriptor contient le résultat de l'appel de la fonction socket ; le numéro du canal de communication


entre le programme et la pile des protocoles réseau.
msg et msgLength correspondent au datagramme et à sa longueur. Ici, on émet des chaînes de caractères
directement vers le correspondant réseau.
(struct sockaddr *) &serverAddress et sizeof(serverAddress) correspondent à la structure de désignation de
l'adresse IP et du numéro de port du serveur puis à la taille de cette structure.
Ensuite, il ne manque plus que la description de la réception des datagrammes renvoyés par le serveur.

<snipped/>
if (recv(socketDescriptor , msg, MAX_MSG , 0) < 0) {
fputs("Aucune réponse du serveur ?", stderr);
close(socketDescriptor);
exit(EXIT_FAILURE);
}

Initiation au développement C sur les sockets 5


Initiation au développement C sur les sockets

socketDescriptor contient le résultat de l'appel de la fonction socket ; le numéro du canal de communication


entre le programme et la pile des protocoles réseau.
msg et MAX_MSG correspondent au datagramme reçu et à sa longueur. Ici, on reçoit des chaînes de caractères
venant directement du correspondant réseau.
Pour toute information complémentaire sur les fonctions utilisées, consulter les pages de manuels
correspondantes. Pour la fonction socket on peut utiliser man 2 socket ou man 7 socket par exemple.

3.2. Code source complet


Code du programme udp-client.c :
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_MSG 100


// 2 caractères pour les codes ASCII '\n' et '\0'
#define MSG_ARRAY_SIZE (MAX_MSG+2)
// Utilisation d'une constante x dans la définition
// du format de saisie
#define str(x) # x
#define xstr(x) str(x)

int main()
{
int socketDescriptor;
int msgLength;
unsigned short int serverPort;
struct sockaddr_in serverAddress;
struct hostent *hostInfo;
struct timeval timeVal;
fd_set readSet;
char msg[MSG_ARRAY_SIZE];

puts("Entrez le nom du serveur ou son adresse IP : ");

memset(msg, 0x0, MSG_ARRAY_SIZE); // Mise à zéro du tampon


scanf("%"xstr(MAX_MSG)"s", msg);

// gethostbyname() reçoit un nom d'hôte ou une adresse IP en notation


// standard 4 octets en décimal séparés par des points puis renvoie un
// pointeur sur une structure hostent. Nous avons besoin de cette structure
// plus loin. La composition de cette structure n'est pas importante pour
// l'instant.
hostInfo = gethostbyname(msg);
if (hostInfo == NULL) {
fprintf(stderr, "Problème dans l'interprétation des informations d'hôte : %s\n", msg);
exit(EXIT_FAILURE);
}

puts("Entrez le numéro de port du serveur : ");


scanf("%hu", &serverPort);

// Création de socket. "PF_INET" correspond à la famille de protocole IPv4.


// "SOCK_DGRAM" correspond à un service de datagramme non orienté connexion.
// "IPPROTO_UDP" désigne le protocole UDP utilisé au niveau transport.
socketDescriptor = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socketDescriptor < 0) {
fputs("Impossible de créer le socket", stderr);
exit(EXIT_FAILURE);
}

// Initialisation des champs de la structure serverAddress


serverAddress.sin_family = hostInfo->h_addrtype;
memcpy((char *) &serverAddress.sin_addr.s_addr,
hostInfo->h_addr_list[0], hostInfo->h_length);
serverAddress.sin_port = htons(serverPort);

puts("\nEntrez quelques caractères au clavier.");


puts("Le serveur les modifiera et les renverra.");
puts("Pour sortir, entrez une ligne avec le caractère '.' uniquement.");
puts("Si une ligne dépasse "xstr(MAX_MSG)" caractères,");
puts("seuls les "xstr(MAX_MSG)" premiers caractères seront utilisés.\n");

// Invite de commande pour l'utilisateur et lecture des caractères jusqu'à la


// limite MAX_MSG. Puis suppression du saut de ligne en mémoire tampon.
puts("Saisie du message : ");
memset(msg, 0x0, MSG_ARRAY_SIZE); // Mise à zéro du tampon
scanf(" %"xstr(MAX_MSG)"[^\n]%*c", msg);

// Arrêt lorsque l'utilisateur saisit une ligne ne contenant qu'un point


while (strcmp(msg, ".")) {
if ((msgLength = strlen(msg)) > 0) {
// Envoi de la ligne au serveur
if (sendto(socketDescriptor, msg, msgLength, 0,

Initiation au développement C sur les sockets 6

Common questions

Alimenté par l’IA

The role of analyzing UDP and TCP with Wireshark in the instructional document is to offer learners practical insights into the real-time behavior and differences in communication patterns of these protocols. This is significant as it allows learners to visually observe how data is transmitted over the network, the effects of connection-oriented versus connectionless communication, and how protocol mechanics are implemented at a detailed level. The hands-on experience provides a robust foundation in understanding network traffic and diagnosing issues, which are essential skills in network programming and debugging .

The document recommends using standard Unix manual pages to understand socket functions as they provide comprehensive documentation that includes descriptions, syntax, and usage examples. This approach is particularly effective due to its depth of detail and the accessibility of the manual pages either through the command line or graphical interfaces. Reference commands like `man 2 socket` or `man 7 socket` facilitate quick access to the necessary information, which helps learners gain a deeper understanding of the functional and technical aspects of sockets .

Using a local loopback interface, such as `127.0.0.1`, is essential when experimenting with client-server socket programs as it allows the same machine to simulate both the client and server, providing a controlled environment for testing. This setup is beneficial for learners as it removes network unpredictability factors like latency or packet loss, concentrating solely on the program's functionality. It also simplifies network configuration, reducing the barriers to initial experimentation and allowing learners to focus on understanding socket communication mechanisms without extraneous complications .

To ensure inputs do not exceed buffer limits during runtime in UDP client applications, the document proposes defining a constant `MAX_MSG` that specifies a maximum allowable number of characters. This constant is used in formats for input functions, preventing overflow by instructing `scanf` to accept a limited number of characters while discarding extra input. By using preprocessor directives to enforce this limit, the code maintains input within safe bounds to avoid runtime errors associated with buffer overflow .

The document emphasizes checking the return values of socket operations and responding to errors by outputting appropriate messages and safely terminating the program. For example, functions like `socket()`, `sendto()`, and `recv()` are wrapped in conditional checks to detect unsuccessful operations, allowing the program to handle errors gracefully. This attention to error management is crucial for robust network programming as it ensures that applications can respond predictively to issues, avoiding crashes and providing informative feedback for debugging and improvement .

The instructional document outlines that the core difference between UDP and TCP socket implementation is the nature of the communication. UDP uses datagram sockets, which are non-connection-oriented, resulting in a simpler socket setup with less overhead. TCP, however, is connection-oriented and entails establishing, maintaining, and terminating connections explicitly, which introduces more complexity in socket programming. Despite these functional differences, the document emphasizes that the socket function calls in C are similar for both protocols, but usage of additional mechanisms like connection handling and flow control distinguishes TCP from UDP in practical network analysis .

The main goal of programming sockets using C according to the document is to provide an introduction to network development using the most minimalistic and portable code possible. This is achieved by employing standard library functions of the C language and restricting the scope to IPv4 addresses at the network layer. Given this introductory objective, the document initially focuses on the UDP protocol for its simplicity and lack of connection orientation, making it less complex for beginners to grasp. Subsequently, the document transitions to using TCP, allowing learners to appreciate differences in implementation and network behavior between UDP and TCP .

The document first introduces socket programming using the UDP protocol and then transitions to TCP. This sequence aids in learning by starting with a simpler connectionless protocol (UDP), which lowers the initial overhead for beginners. Since UDP lacks complex mechanisms like connection establishment and flow control, learners can grasp basic concepts without being overwhelmed. Once the foundational understanding is secured, the document progresses to TCP, which incorporates more intricate concepts of connection management and reliability. This methodical approach helps learners build confidence and prepare for more advanced topics .

The instructional document ensures portability by confining the code examples to utilize network functions that are standard across systems supporting the C language. This includes compiling the client and server code using `gcc` on GNU/Linux systems and employing libraries that are universally accessible, such as standard Unix network libraries. By adhering to IPv4 and fundamental socket function calls, the document maintains compatibility across different systems while focusing on the minimalistic subset of features applicable widely .

User input in a UDP client-server application is carefully handled using `scanf` to read input strings. The syntax `scanf(" %[^ ]%*c", msg);` is used to read a complete string without considering spaces or tabs as delimiters, only terminating at a newline character. The format also removes unwanted newline characters or spaces lingering in the input buffer. Precautions include setting a maximum message length using `MAX_MSG` to prevent buffer overflow, which is applied through preprocessor directives to enforce input limits .

Vous aimerez peut-être aussi