« C socket » : différence entre les versions
Autres actions
| Ligne 162 : | Ligne 162 : | ||
* le code retour correspond au nombre de caractères envoyer ou ''-1'' si une erreur survient (errno est positionné); | * le code retour correspond au nombre de caractères envoyer ou ''-1'' si une erreur survient (errno est positionné); | ||
= | = Cas d'utilisation = | ||
== Création == | |||
Pour commencer, il faut créer le descripteur de fichier: | |||
<source lang="c"> | |||
int fdsocket; | |||
if ((fdsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { | |||
printf("Echéc de la création: %s\n", strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
</source> | |||
== Paramétrage des options == | |||
Il faut maintenant configurer la réutilisation de l'adresse et du port | |||
<source lang="c"> | |||
int opt = 1; | |||
if (setsockopt(fdsocket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) { | |||
printf("Echéc de paramètrage: %s\n", strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
</source> | |||
== Attachement == | |||
On peut maintenant attaché la socket à un port et une adresse: | |||
<source lang="c"> | |||
struct sockaddr_in adresse; | |||
adresse.sin_family = AF_INET; | |||
// Ecoute sur toutes les adresses (INADDR_ANY <=> 0.0.0.0) | |||
adresse.sin_addr.s_addr = INADDR_ANY; | |||
// Conversion du port en valeur réseaux (Host TO Network Short) | |||
adresse.sin_port = htons(8080); | |||
if (bind(fdsocket, (struct sockaddr *) adresse, sizeof(*adresse)) != 0) { | |||
printf("Echéc d'attachement: %s\n", strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
</source> | |||
== Mise en écoute == | |||
La socket est prête à passer à l'écoute des connexions des clients: | |||
<source lang="c"> | |||
// Taille de la file d'attente | |||
#define BACKLOG 3 | |||
if (listen(fdsocket, BACKLOG) != 0) { | |||
printf("Echéc de la mise en écoute: %s\n", strerror(errno)); | |||
exit(EXIT_FAILURE); | |||
} | |||
</source> | |||
== Acceptation des connexions == | |||
Il est possible d'accepter les nouvelles connexions: | |||
<source lang="c"> | |||
int clientSocket; | |||
// Structure contenant l'adresse du client | |||
struct sockaddr_in clientAdresse; | |||
int addrLen = sizeof(clientAdresse); | |||
if ((clientSocket = accept(*serverSocket, (struct sockaddr*) &clientAdresse, (socklen_t*) &addrLen)) != -1) { | |||
// Convertion de l'IP en texte | |||
char ip[INET_ADDRSTRLEN]; | |||
inet_ntop(AF_INET, &(clientAdresse.sin_addr), ip, INET_ADDRSTRLEN); | |||
printf("Connexion de %s:%i\n", ip, clientAdresse.sin_port); | |||
} | |||
</source> | |||
Il est possible d'utiliser ''fcntl'' pour passer le descripteur de la socket en non bloquant, avant l'appel à la fonction ''accept''. Si le descripteur reste bloquant, la fonction ''accept'' ne rendra pas la main tant qu'un client ne se sera connecté, ayant pour résultat le blocage complet du programme ! | |||
<source lang="c"> | |||
// Passage en mode non bloquant | |||
fcntl(fdsocket, F_SETFL, O_NONBLOCK); | |||
</source> | |||
== Lecture / Écriture == | |||
On peut maintenant utiliser le descripteur de la socket du client pour lire et écrire. | |||
* avec les fonctions génériques: | |||
<source lang="c"> | |||
#define BUFFER_LEN 200 | |||
// Descripteur de la socket du client | |||
int clientSocket; | |||
char buffer[BUFFER_LEN]; | |||
// Passage en mode non bloquant, sinon read est bloquant | |||
fcntl(clientSocket, F_SETFL, O_NONBLOCK); | |||
int len = read(clientSocket, buffer, BUFFER_LEN); | |||
send(clientSocket, "Coucou\n", strlen("Coucou\n")); | |||
</source> | |||
* avec les fonctions spécifiques: | |||
<source lang="c"> | |||
#define BUFFER_LEN 200 | |||
// Descripteur de la socket du client | |||
int clientSocket; | |||
char buffer[BUFFER_LEN]; | |||
int len = recv(clientSocket, buffer, BUFFER_LEN, MSG_DONTWAIT); | |||
send(clientSocket, "Coucou\n", strlen("Coucou\n"), MSG_DONTWAIT); | |||
</source> | |||
== Serveur mono-utilisateur == | == Serveur mono-utilisateur == | ||
Voici un exemple de serveur ''echo'' qui renvoie le message au client. | Voici un exemple de serveur ''echo'' qui renvoie le message au client. | ||
| Ligne 174 : | Ligne 263 : | ||
#include <errno.h> | #include <errno.h> | ||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||
#include <fcntl.h> | |||
// Port d'écoute de la socket | // Port d'écoute de la socket | ||
| Ligne 181 : | Ligne 271 : | ||
// Taille de la file d'attente | // Taille de la file d'attente | ||
#define BACKLOG 3 | #define BACKLOG 3 | ||
// Nombre de connexions clients | |||
#define NB_CLIENTS 2 | |||
// Message à envoyer au client | // Message à envoyer au client | ||
# define WELCOME_MESSAGE "Entrez 'exit' pour quitter\n" | # define WELCOME_MESSAGE "Entrez 'exit' pour quitter\n" | ||
| Ligne 193 : | Ligne 285 : | ||
int main(void) { | int main(void) { | ||
// Création et initialisation du tableau contenant les clients | |||
int clients[NB_CLIENTS]; | |||
for (int i = 0; i < NB_CLIENTS; i++) { | |||
clients[i] = -1; | |||
} | |||
int nbClients = 0; | |||
// Structure contenant l'adresse | // Structure contenant l'adresse | ||
struct sockaddr_in adresse; | struct sockaddr_in adresse; | ||
| Ligne 198 : | Ligne 296 : | ||
// Descripteur de la socket du serveur | // Descripteur de la socket du serveur | ||
int serverSocket = initSocket(&adresse); | int serverSocket = initSocket(&adresse); | ||
// Création d'un tampon pour stocker les messages des clients | |||
char buffer[BUFFER_LEN + 1]; | |||
while (1) { | while (1) { | ||
// Descripteur de la socket du client, on attend une connexion | if (nbClients < NB_CLIENTS) { | ||
// Descripteur de la socket du client, on attend une connexion | |||
int clientSocket = waitForClient(&serverSocket); | |||
if (clientSocket != -1) { | |||
// On vérifie si on à de la place de libre | |||
int found = -1; | |||
int len = | for (int i = 0; i < NB_CLIENTS; i++) { | ||
// Ajout du terminateur de chaîne | if (clients[i] == -1) { | ||
// On ajoute le client | |||
printf("Ajout du client à l'index %i\n", i); | |||
clients[i] = clientSocket; | |||
// Nouvelle connexion, envoie du message de bienvenu | |||
write(clientSocket, WELCOME_MESSAGE, | |||
strlen(WELCOME_MESSAGE)); | |||
found = 0; | |||
nbClients++; | |||
break; | |||
} | |||
} | |||
if (found == -1) { | |||
// On a plus de place de libre | |||
send(clientSocket, "Plus de place, désolé\n", | |||
strlen("Plus de place, désolé\n"), 0); | |||
close(clientSocket); | |||
} | |||
} | |||
} | |||
for (int i = 0; i < NB_CLIENTS; i++) { | |||
// On vérifie les messages | |||
int clientSocket = clients[i]; | |||
if(clientSocket == -1){ | |||
continue; | |||
} | |||
int len = recv(clientSocket, buffer, BUFFER_LEN, MSG_DONTWAIT); | |||
// On vérifie que la socket n'est pas fermé | |||
if (len == -1 && errno != EAGAIN) { | |||
printf("Errno [%i] : %s\n", errno, strerror(errno)); | |||
// La socket est fermé, on libère de la place | |||
close(clientSocket); | |||
clients[i] = -1; | |||
nbClients--; | |||
} else if (len > 0) { | |||
// Ajout du terminateur de chaîne | |||
buffer[len] = '\0'; | |||
if (strncmp(buffer, EXIT_WORD, 4) == 0) { | |||
// On ferme la socket | |||
send(clientSocket, "Bye\n", strlen("Bye\n"), 0); | |||
printf("Fermeture de la connexion avec le client\n"); | |||
close(clientSocket); | |||
clients[i] = -1; | |||
nbClients--; | |||
} else { | |||
// On renvoie le texte au client | |||
write(clientSocket, "Vous avez dit : ", | |||
strlen("Vous avez dit : "), 0); | |||
send(clientSocket, buffer, strlen(buffer), 0); | |||
} | |||
} | |||
} | } | ||
} | } | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
| Ligne 254 : | Ligne 397 : | ||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||
} | } | ||
// Passage en mode non bloquant | |||
fcntl(fdsocket, F_SETFL, O_NONBLOCK); | |||
printf("Mise en écoute de la socket\n"); | printf("Mise en écoute de la socket\n"); | ||
return fdsocket; | return fdsocket; | ||
| Ligne 263 : | Ligne 408 : | ||
struct sockaddr_in clientAdresse; | struct sockaddr_in clientAdresse; | ||
int addrLen = sizeof(clientAdresse); | int addrLen = sizeof(clientAdresse); | ||
if ((clientSocket = accept(*serverSocket, (struct sockaddr*) &clientAdresse, | if ((clientSocket = accept(*serverSocket, (struct sockaddr*) &clientAdresse, | ||
(socklen_t*) &addrLen)) | (socklen_t*) &addrLen)) != -1) { | ||
printf(" | // Convertion de l'IP en texte | ||
char ip[INET_ADDRSTRLEN]; | |||
inet_ntop(AF_INET, &(clientAdresse.sin_addr), ip, INET_ADDRSTRLEN); | |||
printf("Connexion de %s:%i\n", ip, clientAdresse.sin_port); | |||
// Passage en mode non bloquant | |||
int opt = 1; | |||
setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(1)); | |||
//fcntl(clientSocket, F_SETFL, O_NONBLOCK|SO_KEEPALIVE); | |||
} | } | ||
return clientSocket; | return clientSocket; | ||
} | } | ||
</source> | </source> | ||
== Serveur multi-utilisateurs == | == Serveur multi-utilisateurs == | ||
Version du 27 octobre 2018 à 18:32
Introduction
Création
Côté serveur
Tout d'abord il faut créer l'objet socket:
#include <sys/socket.h> #include <netinet/in.h> int socket(int domain, int type, int protocol)
- domain → integer, communication domain e.g., AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)
- type → type de communication
- SOCK_STREAM: TCP
- SOCK_DGRAM: UDP
- SOCK_RAW: socket à l'état brut (bas niveau)
- protocol → valeur du champ protocol de l'entête de niveau 3 (généralement 0)
- la valeur de retour est le fichier descripteur de la socket ou -1 en cas d'erreur (errno est positionné)
Une fois le descripteur de socket créé, il est possible de le configurer:
#include <sys/socket.h> #include <netinet/in.h> int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
- sockfd → le fichier descripteur de la socket;
- level → niveau d'application de l'option (SOL_SOCKET, TCP, UDP, ...);
- optname → le nom de l'option (SO_REUSEADDR, SO_REUSEPORT, SO_KEEPALIVE, ...)
- optval, optlen → utilisé pour accéder aux options de la socket;
- le code retour varie entre 0 et -1 en cas d'erreur (errno est positionné)
Il existe plusieurs options de socket, les plus utilisées étant :
- SO_REUSEADDR → permet de réutiliser l'adresse de la socket tout de suite même si cette dernière est dans l'état wait;
- SO_REUSEPORT → permet de réutiliser le port de la socket tout de suite même si cette dernière est dans l'état wait;
- SO_KEEPALIVE → envoie des informations périodiquement pour tester si l'extrémité du tunnel est toujours présente;
Il faut maintenant attacher la socket à un port Internet et une adresse IP:
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
- sockfd → le fichier descripteur de la socket;
- addr → une structure symbolisant l'adresse
struct sockaddr_in {
short sin_family; // e.g: AF_INET
unsigned short sin_port; // e.g: htons(3490)
struct in_addr sin_addr; // détaillé ci-dessous
char sin_zero[8]; // '0' habituellement
};
struct in_addr {
unsigned long s_addr; // initialiser avec inet_aton()
};
- addrlen → la taille de l'objet addr;
- le code retour varie entre 0 et -1 en cas d'erreur (errno est positionné)
On peut maintenant passer la socket en état d'écoute, elle est prête à recevoir des connexions:
int listen(int sockfd, int backlog)
- sockfd → le fichier descripteur de la socket;
- backlog → taille maximum de la file d'attente de la socket après laquelle le système répond avec ECONNREFUSED;
- le code retour varie entre 0 et -1 en cas d'erreur (errno est positionné)
On peut maintenant attendre une connexion:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- sockfd → le fichier descripteur de la socket;
- addr → l'adresse du client;
- addrlen → la taille de la structure addr;
- le code retour varie entre un entier positif qui correspond au descripteur de la socket cliente et -1 en cas d'erreur (errno est positionné)
Côté client
Après avoir créé la socket avec socket on peut se connecter à la partie serveur:
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd → le fichier descripteur de la socket;
- addr → une structure symbolisant l'adresse (cf. ci-dessus)
- addrlen → la taille de l'objet addr;
- le code retour varie entre 0 et -1 en cas d'erreur (errno est positionné)
Lecture / écriture
Fonctions génériques
Tout d'abord, on peut dire que la socket est un fichier et se manipule donc comme un fichier !
Lecture
Pour lire dans une socket on peut utiliser read:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
- sockfd → le fichier descripteur de la socket;
- buf → le tableau de caractères ou mettre le message reçu;
- count → le nombre de caractères à recevoir;
- le code retour correspond au nombre de caractères reçu ou -1 si une erreur survient (errno est positionné);
Écriture
Pour écrire dans une socket ou peut utiliser write:
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
- sockfd → le fichier descripteur de la socket;
- buf → le tableau de caractères contenant le message à envoyer;
- count → le nombre de caractères à envoyer;
- le code retour correspond au nombre de caractères envoyer ou -1 si une erreur survient (errno est positionné);
Modification
Pour modifier un descripteur fichier de socket on utilise fcntl:
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* int args */ );
- sockfd → le fichier descripteur de la socket;
- cmd → la commande de modification (descripteur, drapeaux, ...);
- args → les arguments correspondants à la commande
Cette commande va nous permettre de modifier le drapeaux du descripteur de la socket (F_SETFL) pour le rendre non bloquant (O_NONBLOCK) !
Fonctions spécifiques
Il existe des fonctions spécifiques pour manipuler les sockets. Ces fonctions ressemble au précédentes mais acceptent des drapeaux en plus pour pouvoir modifier le descripteur à la volé.
Lecture
Pour lire dans une socket on peut utiliser recv:
#include <unistd.h> ssize_t recv(int fd, void *buf, size_t count, int flags);
- sockfd → le fichier descripteur de la socket;
- buf → le tableau de caractères ou mettre le message reçu;
- count → le nombre de caractères à recevoir;
- flags → liste de drapeaux (eg. O_NONBLOCK);
- le code retour correspond au nombre de caractères reçu ou -1 si une erreur survient (errno est positionné);
Écriture
Pour écrire dans une socket ou peut utiliser send:
#include <unistd.h> ssize_t send(int fd, const void *buf, size_t count);
- sockfd → le fichier descripteur de la socket;
- buf → le tableau de caractères contenant le message à envoyer;
- count → le nombre de caractères à envoyer;
- flags → liste de drapeaux (eg. MSG_CONFIRM, MSG_DONTWAIT , ...);
- le code retour correspond au nombre de caractères envoyer ou -1 si une erreur survient (errno est positionné);
Cas d'utilisation
Création
Pour commencer, il faut créer le descripteur de fichier:
int fdsocket;
if ((fdsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("Echéc de la création: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
Paramétrage des options
Il faut maintenant configurer la réutilisation de l'adresse et du port
int opt = 1;
if (setsockopt(fdsocket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) {
printf("Echéc de paramètrage: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
Attachement
On peut maintenant attaché la socket à un port et une adresse:
struct sockaddr_in adresse;
adresse.sin_family = AF_INET;
// Ecoute sur toutes les adresses (INADDR_ANY <=> 0.0.0.0)
adresse.sin_addr.s_addr = INADDR_ANY;
// Conversion du port en valeur réseaux (Host TO Network Short)
adresse.sin_port = htons(8080);
if (bind(fdsocket, (struct sockaddr *) adresse, sizeof(*adresse)) != 0) {
printf("Echéc d'attachement: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
Mise en écoute
La socket est prête à passer à l'écoute des connexions des clients:
// Taille de la file d'attente
#define BACKLOG 3
if (listen(fdsocket, BACKLOG) != 0) {
printf("Echéc de la mise en écoute: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
Acceptation des connexions
Il est possible d'accepter les nouvelles connexions:
int clientSocket;
// Structure contenant l'adresse du client
struct sockaddr_in clientAdresse;
int addrLen = sizeof(clientAdresse);
if ((clientSocket = accept(*serverSocket, (struct sockaddr*) &clientAdresse, (socklen_t*) &addrLen)) != -1) {
// Convertion de l'IP en texte
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(clientAdresse.sin_addr), ip, INET_ADDRSTRLEN);
printf("Connexion de %s:%i\n", ip, clientAdresse.sin_port);
}
Il est possible d'utiliser fcntl pour passer le descripteur de la socket en non bloquant, avant l'appel à la fonction accept. Si le descripteur reste bloquant, la fonction accept ne rendra pas la main tant qu'un client ne se sera connecté, ayant pour résultat le blocage complet du programme !
// Passage en mode non bloquant fcntl(fdsocket, F_SETFL, O_NONBLOCK);
Lecture / Écriture
On peut maintenant utiliser le descripteur de la socket du client pour lire et écrire.
- avec les fonctions génériques:
#define BUFFER_LEN 200
// Descripteur de la socket du client
int clientSocket;
char buffer[BUFFER_LEN];
// Passage en mode non bloquant, sinon read est bloquant
fcntl(clientSocket, F_SETFL, O_NONBLOCK);
int len = read(clientSocket, buffer, BUFFER_LEN);
send(clientSocket, "Coucou\n", strlen("Coucou\n"));
- avec les fonctions spécifiques:
#define BUFFER_LEN 200
// Descripteur de la socket du client
int clientSocket;
char buffer[BUFFER_LEN];
int len = recv(clientSocket, buffer, BUFFER_LEN, MSG_DONTWAIT);
send(clientSocket, "Coucou\n", strlen("Coucou\n"), MSG_DONTWAIT);
Serveur mono-utilisateur
Voici un exemple de serveur echo qui renvoie le message au client.
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
// Port d'écoute de la socket
#define PORT 8080
// Adresse d'écoute (toutes les adresses)
#define IP INADDR_ANY
// Taille de la file d'attente
#define BACKLOG 3
// Nombre de connexions clients
#define NB_CLIENTS 2
// Message à envoyer au client
# define WELCOME_MESSAGE "Entrez 'exit' pour quitter\n"
// Taille du tampon de lecture des messages
#define BUFFER_LEN 200
// Commande pour arrêter le serveur
#define EXIT_WORD "exit"
void initAdresse(struct sockaddr_in * adresse);
int initSocket(struct sockaddr_in * adresse);
int waitForClient(int * serverSocket);
int main(void) {
// Création et initialisation du tableau contenant les clients
int clients[NB_CLIENTS];
for (int i = 0; i < NB_CLIENTS; i++) {
clients[i] = -1;
}
int nbClients = 0;
// Structure contenant l'adresse
struct sockaddr_in adresse;
initAdresse(&adresse);
// Descripteur de la socket du serveur
int serverSocket = initSocket(&adresse);
// Création d'un tampon pour stocker les messages des clients
char buffer[BUFFER_LEN + 1];
while (1) {
if (nbClients < NB_CLIENTS) {
// Descripteur de la socket du client, on attend une connexion
int clientSocket = waitForClient(&serverSocket);
if (clientSocket != -1) {
// On vérifie si on à de la place de libre
int found = -1;
for (int i = 0; i < NB_CLIENTS; i++) {
if (clients[i] == -1) {
// On ajoute le client
printf("Ajout du client à l'index %i\n", i);
clients[i] = clientSocket;
// Nouvelle connexion, envoie du message de bienvenu
write(clientSocket, WELCOME_MESSAGE,
strlen(WELCOME_MESSAGE));
found = 0;
nbClients++;
break;
}
}
if (found == -1) {
// On a plus de place de libre
send(clientSocket, "Plus de place, désolé\n",
strlen("Plus de place, désolé\n"), 0);
close(clientSocket);
}
}
}
for (int i = 0; i < NB_CLIENTS; i++) {
// On vérifie les messages
int clientSocket = clients[i];
if(clientSocket == -1){
continue;
}
int len = recv(clientSocket, buffer, BUFFER_LEN, MSG_DONTWAIT);
// On vérifie que la socket n'est pas fermé
if (len == -1 && errno != EAGAIN) {
printf("Errno [%i] : %s\n", errno, strerror(errno));
// La socket est fermé, on libère de la place
close(clientSocket);
clients[i] = -1;
nbClients--;
} else if (len > 0) {
// Ajout du terminateur de chaîne
buffer[len] = '\0';
if (strncmp(buffer, EXIT_WORD, 4) == 0) {
// On ferme la socket
send(clientSocket, "Bye\n", strlen("Bye\n"), 0);
printf("Fermeture de la connexion avec le client\n");
close(clientSocket);
clients[i] = -1;
nbClients--;
} else {
// On renvoie le texte au client
write(clientSocket, "Vous avez dit : ",
strlen("Vous avez dit : "), 0);
send(clientSocket, buffer, strlen(buffer), 0);
}
}
}
}
return EXIT_SUCCESS;
}
// Initialisation de la structure sockaddr_in
void initAdresse(struct sockaddr_in * adresse) {
(*adresse).sin_family = AF_INET;
(*adresse).sin_addr.s_addr = IP;
(*adresse).sin_port = htons( PORT);
}
// Démarrage de la socket serveur
int initSocket(struct sockaddr_in * adresse) {
// Descripteur de socket
int fdsocket;
// Nombre d'options
int opt = 1;
// Création de la socket en TCP
if ((fdsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("Echéc de la création: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Création de la socket\n");
// Paramètrage de la socket
if (setsockopt(fdsocket, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
sizeof(opt)) != 0) {
printf("Echéc de paramètrage: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Paramètrage de la socket\n");
// Attachement de la socket sur le port et l'adresse IP
if (bind(fdsocket, (struct sockaddr *) adresse, sizeof(*adresse)) != 0) {
printf("Echéc d'attachement: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Attachement de la socket sur le port %i\n", PORT);
// Passage en écoute de la socket
if (listen(fdsocket, BACKLOG) != 0) {
printf("Echéc de la mise en écoute: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// Passage en mode non bloquant
fcntl(fdsocket, F_SETFL, O_NONBLOCK);
printf("Mise en écoute de la socket\n");
return fdsocket;
}
// Attente de connexion d'un client
int waitForClient(int * serverSocket) {
int clientSocket;
// Structure contenant l'adresse du client
struct sockaddr_in clientAdresse;
int addrLen = sizeof(clientAdresse);
if ((clientSocket = accept(*serverSocket, (struct sockaddr*) &clientAdresse,
(socklen_t*) &addrLen)) != -1) {
// Convertion de l'IP en texte
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(clientAdresse.sin_addr), ip, INET_ADDRSTRLEN);
printf("Connexion de %s:%i\n", ip, clientAdresse.sin_port);
// Passage en mode non bloquant
int opt = 1;
setsockopt(clientSocket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(1));
//fcntl(clientSocket, F_SETFL, O_NONBLOCK|SO_KEEPALIVE);
}
return clientSocket;
}
