Différences entre versions de « C socket »
(Page créée avec « = Introduction = {| |- || Les sockets permettent de connecter deux programmes qui s'exécutent sur deux machines différentes. Cette connexion se fait à travers le résea... ») |
|||
Ligne 12 : | Ligne 12 : | ||
|} | |} | ||
= Utilisation = | = Utilisation = | ||
+ | == Côté serveur == | ||
Tout d'abord il faut créer l'objet socket: | Tout d'abord il faut créer l'objet socket: | ||
<source lang="c"> | <source lang="c"> | ||
Ligne 25 : | Ligne 26 : | ||
**SOCK_RAW: socket à l'état brut (bas niveau) | **SOCK_RAW: socket à l'état brut (bas niveau) | ||
*protocol → valeur du champ ''protocol'' de l'entête de niveau 3 (généralement ''0'') | *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 | + | *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: | ||
<source lang="c"> | <source lang="c"> | ||
#include <sys/socket.h> | #include <sys/socket.h> | ||
Ligne 32 : | Ligne 36 : | ||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) | int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) | ||
</source> | </source> | ||
+ | * 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: | ||
<source lang="c"> | <source lang="c"> | ||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) | ||
</source> | </source> | ||
+ | * sockfd → le fichier descripteur de la socket; | ||
+ | * addr → une structure symbolisant l'adresse | ||
+ | <source lang="c"> | ||
+ | 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() | ||
+ | }; | ||
+ | </source> | ||
+ | * 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: | ||
<source lang="c"> | <source lang="c"> | ||
int listen(int sockfd, int backlog) | int listen(int sockfd, int backlog) | ||
</source> | </source> | ||
+ | * 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: | ||
<source lang="c"> | <source lang="c"> | ||
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); | ||
</source> | </source> | ||
− | + | * 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: | ||
<source lang="c"> | <source lang="c"> | ||
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | ||
</source> | </source> | ||
+ | * 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é) | ||
+ | |||
+ | = Exemple = | ||
+ | == Côté serveur == | ||
+ | |||
+ | == Côté client == |
Version du 26 octobre 2018 à 11:23
Introduction
Les sockets permettent de connecter deux programmes qui s'exécutent sur deux machines différentes. Cette connexion se fait à travers le réseau grâce à l'utilisation d'un port (TCP ou UDP) et d'une adresse IP. Il y a deux types de sockets, une qui est démarrée par la partie serveur en écoute et l'autre démarrée par la partie cliente qui se connecte à la première. Ci-contre une image résumant les différentes étapes pour arriver à l'envoie de données. |
Utilisation
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é)