Différences entre versions de « C socket »

De The Linux Craftsman
Aller à la navigation Aller à la recherche
(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 &rarr; valeur du champ ''protocol'' de l'entête de niveau 3 (généralement ''0'')
 
*protocol &rarr; 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 &rarr; le fichier descripteur de la socket;
 +
* level &rarr; niveau d'application de l'option (SOL_SOCKET, TCP, UDP, ...);
 +
* optname &rarr; le nom de l'option (''SO_REUSEADDR'', ''SO_REUSEPORT'', ''SO_KEEPALIVE'', ...)
 +
* optval, optlen  &rarr; 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'' &rarr; 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'' &rarr; 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'' &rarr; 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 &rarr; le fichier descripteur de la socket;
 +
* addr &rarr; 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 &rarr; 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 &rarr; le fichier descripteur de la socket;
 +
* backlog &rarr; 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 &rarr; le fichier descripteur de la socket;
 +
* addr &rarr; l'adresse du client;
 +
* addrlen &rarr; 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 &rarr; le fichier descripteur de la socket;
 +
* addr &rarr; une structure symbolisant l'adresse (cf. ci-dessus)
 +
* addrlen &rarr; 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 à 12: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.

Socket workflow.png

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é)

Exemple

Côté serveur

Côté client