²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² ² 9°/Programmation de sockets ² ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² a) Présentation d'une socket ----------------------------- Bon, pour commencer, il serait intéressant de savoir qu'est ce qu'une socket. Une socket est un API (Application Programm Interface) qui permet le transfert de données entre deux processeurs distants ou non. Au plan matériel, la socket est une "carte" qui relie la carte mère au processeur. Enfin, bref, pour communiquer, nous allons devoir créer une socket sur le client et tenter de la connecter à une socket sur le serveur. En C, la création d'une socket se présentez sous cette forme : int socket(int domain, int type, int protocol); Cette socket est définie par trois éléments, dont voici les détails : -domain: C'est le domaine d'adressage de la socket, qui peut être soit *AF_INET (pour internet) *AF_UNIX (pour la communication inter-processus sous UNIX) -type: Il s'agit du type de la socket, de la façon dont la socket va trasporter les données. On distingue plusieurs modes, qui contiennent différent types de socket. Ces modes sont les suivants : *Direct protocol: Ce mode recouvre SOCK_RAW (pour écrire directement dans ses packets ip). *Mode connecté: SOCK_DGRAM *Mode non-connecté: SOCK_STREAM -protocol: Cet élément définit le protocole utilisé par la socket. Voici ces différents types de protocoles : *0: C'est le protocole par défaut. C'est le système qui déterminera le type de protocole, UDP pour le mode non-connecté et TCP pour le mode connecté. *IPPROTO_UDP: Pour le protocole UDP (User Datagramm Protocol). *IPPROTO_TCP: Pour le protocole TCP (Transmission Control Protocol). Voilà, clair non? Voici maintenant un exemple de socket: Kefka = socket(AF_INET, SOCK_DGRAM, 0) Cette socket, qui répond au doux nom de Kefka (;)), est une socket qui possède un domaine d'adressage Internet, en mode non-connecté, et donc qui utilise le protocole UDP. On aurait aussi pu écrire: Kefka = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) mais ça nous rallonge beaucoup trop, alors dans presque tous les cas le type de protocole utilisé sera 0, donc on laissera le choix au système. b)Récupération des information de l'host ----------------------------------------- Bon, on a notre socket, c'est bien , mais le tout est de pouvoir la raccorder à quelque chose, càd la socket distante, située sur le serveur. Il va évidemment nous falloir l'adresse de la socket distante, afin de pouvoir établir une communication avec celle-ci. Nous allons utiliser pour cela la structure sockaddr_in ( in pour Internet), car en effet la structure sockaddr mise toute seule est une structure qui recouvre tous les type de socket, trop générique pour la socket que nous avons créer donc. Cette structure se présente donc comme ceci : struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8] } Voilà la définition des parties de ces structures: -sin_family , qui va représenter la famille de l'adressage de la socket, qui dans notre cas va être AF_INET. -sin_port , qui va représenter le numéro de port en format réseau, sur lequel la socket écoute. -sin_addr , qui va représenter l'adresse ip en format réseau de la machine serveur (sur laquelle on veut connecter notre socket). -sin_zero[8] , qui va représenter un tableau de 8 caractères, cette partie est facultative, oublions la. Voici un exemple d'initialisation de cette structure : struct sockaddr_in addrSock; addrSock.sin_family = AF_INET; addrSock.sin_port = htons(Port); addrSock.sin_addr = *(struct_in addr *) serveur->h_addr; Bon, c'est pas très clair pour l'instant, je le reconnais. La fonction htons() s'occupe de la conversion du numéro de port au format réseau. Pour ce qui est de la partie addrSock.sin_addr, suivi de *(struct_in addr *) serveur->h_addr, vous allez comprendre par la suite ne vous inquiétez pas. Bon, pour se connecter à notre socket, il faut peut être savoir où elle se trouve. La structure hostent va s'occuper de cela. Cette structure va convertir les informations relatives au serveur où se trouve le socket sur lequel on désire se connecter. Et voilà comment se présente cette structure : struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_lenght; chat **h_addr_list } Héhéhé, ça doit vous rapeller des choses ça... Et voilà à quoi correspondent ces différents éléments : -h_name: Il s'agit d'une chaîne de caractère représentant le nom d'host de la machine. -h_aliases: Il s'agit d'une chaîne de caractères contenant les alias (facultatifs) de la machine. -h_addrtype: Il s'agit du type d'adresse de l'host, qui sera bien entendu Ipv4 (et oui, Ipv6, c'est pas encore :)) ). -h_lenght: Il s'agit de la longueur de l'adresse. -h_addr_list: Il s'agit d'un tableau de caractères contenant la liste des adresses de cet host. Et voilà, tout s'éclaire !!! Vous savez désormais que *(struct in_addr *) serveur h_addr va représenter l'adresse de l'host. Nous allons maintenant récupérer des infos sur la machine, grâce à la fonction gethostbyname(). Voilà comment se présente cette fonction : struct hostent *gethostbyname(const char *name); Cette fonction renvoie un pointeur sur la structure hostent. Voici un exemple de l'utilisation de cette fonction : struct hostent Host; Host = gethostbyname(MachineName); Cette fonction va utiliser le nom de la machine (MachineName) pour récupérer des informations sur l'host. c)Connection de la socket -------------------------- Nous avons maintenant créer notre socket, nous avons défini l'adresse d'une socket distante et nous avons récupérer des informations sur la machine sur laquelle se trouve le socket. Nous allons maintenant connecter notre socket avec celle de la machine distante. Et pour cela, on va utiliser la fonction connnect : int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen); Et voilà le détail des éléments de cette fonction : -sockfd: C'est le nom de notre socket. -struct sockaddr *serv_addr: C'est un pointeur vers une structure de type sockaddr, qui est notre adresse de socket. -socklent_t addrlen: C'est la taille de notre structure sockaddr. Si la fonction renvoie une valeur supérieure ou égale à zéro, la connection est établie, si la valeur renvoyée est strictement inférieure à zéro, la connection n'est pas établie. Enfin, la dernière fonction que l'on utilisera sera close(), pour fermer notre socket. Voilà vous savez tout !!!