9
1 Les Sockets en C  pour utiliser ces primitives il faudra obligatoirement inclu re les bibliothèques suivantes dans votre  programme : #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> Les structures de données : Cette structure permet de stocker les informations sur les adresses des sockets utilisés struct sockaddr { unsigned short sa_fami ly ; // la famille d’adresse char sa_data[14]; // 14 octets pour l’adresse du protocole }; La famille de protocole essentiellement utilisée est : AF_INET struct sockaddr_in { short int sin_family; // Famille d’adresse unsigned short int sin_port; // le numero de port struct in_addr sin_addr; // Adresse IP unsigned char sin_zero[8]; // non utilisé }; In signifie Internet. Cette structure permet en plus de preciser le numéro de port d’ecoute ainsi que l’adresse du serveur. La structure sockaddr_in peut être castée en une structure de type sockaddr struct in_addr { unsigned long s_addr; }; Cette structure permet de st ocker l’adresse IP d’une machine Les fonction de conversion de données (byte ordering) htons() – "Host to Network Short" htonl() – "Host to Network Long" ntohs() – "Network to Host Short" ntohl() – "Network to Host Long" Récupération de l’adresse Ip d’une machine Si vous voulez stocker l’adresse IP d’une machine dans la structure sockaddr_in Utilisez la fonction inet_addr() exemple : V ous avez cette déclaration : struct sockaddr_in adresseIP ; adresseIP .sin_addr .s_addr=inet_addr(“192.168.1.1 ”) la fonction inet_addr convertit l’adresse IP en un bloc d’octets ordonné lisible sur le reseau. Elle retourne -1 si erreur. On peut également utiliser la fonction inet_aton à la place de inet_addr.

Les Sockets en C

Embed Size (px)

Citation preview

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 1/9

1

Les Sockets en C

 pour utiliser ces primitives il faudra obligatoirement inclure les bibliothèques suivantes dans votre

 programme :#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>#include <sys/types.h>

#include <sys/socket.h>

Les structures de données :

Cette structure permet de stocker les informations sur les adresses des sockets utilisés

struct sockaddr {

unsigned short sa_family; // la famille d’adresse

char sa_data[14]; // 14 octets pour l’adresse du protocole

};

La famille de protocole essentiellement utilisée est : AF_INET

struct sockaddr_in {

short int sin_family; // Famille d’adresse

unsigned short int sin_port; // le numero de port

struct in_addr sin_addr; // Adresse IP

unsigned char sin_zero[8]; // non utilisé

};

In signifie Internet. Cette structure permet en plus de preciser le numéro de port d’ecoute ainsi que l’adresse

du serveur.La structure sockaddr_in peut être castée en une structure de type sockaddr 

struct in_addr {

unsigned long s_addr;

};

Cette structure permet de stocker l’adresse IP d’une machine

Les fonction de conversion de données (byte ordering)

htons() – "Host to Network Short"

htonl() – "Host to Network Long"

ntohs() – "Network to Host Short"

ntohl() – "Network to Host Long"

Récupération de l’adresse Ip d’une machine

Si vous voulez stocker l’adresse IP d’une machine dans la structure sockaddr_in

Utilisez la fonction inet_addr() exemple :

Vous avez cette déclaration :

struct sockaddr_in adresseIP ;

adresseIP.sin_addr.s_addr=inet_addr(“192.168.1.1”)

la fonction inet_addr convertit l’adresse IP en un bloc d’octets ordonné lisible sur le reseau. Elle retourne -1si erreur.

On peut également utiliser la fonction inet_aton à la place de inet_addr.

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 2/9

2

aton veut dire ascii to network. Permet de récupérer l’adresse Ip sous forme de chaine de caractère et de le

mettre dans un format réseau.

int inet_aton(const char *cp, struct in_addr *inp);

Exemple d’utilisation de inet_aton :

struct sockaddr_in my_addr;

my_addr.sin_family = AF_INET;my_addr.sin_port = htons(MYPORT);// entire court vers réseau

inet_aton("10.12.110.57", &(my_addr.sin_addr));

memset(&(my_addr.sin_zero), ’\0’, 8); //met a zero le reste de la

structure

Si vous voulez affichez l’adresse IP d’une machine il suffit d’utiliser la fonction inet_ntoa.

 Ntoa veut dire network to ascii. Ntoa renvoie l’adresse IP sous forme de chaine de caractère.

Exemple d’utilisation :

printf("%s", inet_ntoa(adresseIP.sin_addr));

char *a1, *a2;

.

.

a1 = inet_ntoa(ina1.sin_addr); // this is 192.168.4.14

a2 = inet_ntoa(ina2.sin_addr); // this is 10.12.110.57

printf("address 1: %s\n",a1);

printf("address 2: %s\n",a2);

Les primitives de base des sockets

Le primitive socket :Elle permet de créer une socket et renvoie son descripteur 

int socket(int domain,int type, int protocol)

l'entier renvoyé par la primitive socket est le descripteur de la socket créée.

Elle renvoie la valeur -1 s'il y'a erreur.

 Domain : représente la famille de protocole utilisée. Dans notre cas la famille de protocole internet

qui sera utilisée : AF_INET.

type : représente le type de socket à utiliser. Il y'a deux types de socket, les sockets en mode flux

(SOCK_STREAM) pour une communication en mode connecté et les sockets en mode datagramme

(SOCK_DRAM) pour la communication en mode non connecté.

 Protocol : représente le protocole de niveau transport à utiliser. Sa valeur par défaut est 0. le fait de

mettre 0 à la place du champ protocol permet de dire a la primitive socket de détecter automatique le

 protocole de transport à utiliser en fonction du type de socket.

La primitive bind :

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

Il permet de definer le port d’écoute du serveur ainsi que

les adresses IP valides du serveur.

Sockfd est le descripteur de la socket renvoyé par la primitive socket(). My_addr est un pointeur sur 

la structure contenant , la famille d’adresse de la socket, l’adresse IP du serveur ainsi que le numéro

de port d’écoute du serveur.

addrlen represente la longueur en octet de la structure sock_addr il peut etre obtenu en utilisant

l’operateur sizeof.

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 3/9

3

Exemple d’une portion de programme :#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#define MYPORT 3490

main(){

int sockfd;

struct sockaddr_in my_addr;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

my_addr.sin_family = AF_INET;

my_addr.sin_port = htons(MYPORT);

my_addr.sin_addr.s_addr = inet_addr("10.12.110.57");

memset(&(my_addr.sin_zero), ’\0’, 8);

bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));

.

.

Deux remarques importantes avec bind :my_addr.sin_port = 0; // vous demandez a bind de choisir pour vous un numero de

 port. La valeut choisie sera arbitraire.

my_addr.sin_addr.s_addr = INADDR_ANY; // bind utilisera toutes les addresses

valide de la machine lors des ecoutes

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 4/9

4

La primitive sendto et recvfrom

Elles sont utilisées en mode non connecté pour l’envoie et la réception des

données

int sendto(int sockfd, const void *msg, int len, unsigned int flags,const

struct sockaddr *to, int tolen);

int recvfrom(int sockfd, void *buf, int len, unsigned int flags,struct

sockaddr *from, int *fromlen);

recvfrom renvoie -1 en cas d’erreur sinon elle renvoie le nombre d’octets

reçus (de meme que sendto).

Les primitives de gestion de nom

Pour utiliser ces primitives, il faut disposer d’un service de nom sur le réseau. Mais pour des tests en local,

on pourra juste utiliser le fichier hosts.

La primitive getpeername

répond à la question qui es-tu ?

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);

permet de recuperer les informations sur l’hote qui s’ext connecté.

on pourra ensuite utiliser inet_ntoa pour afficher son adresse IP.

La primitive gethostname

Répond à la question qui suis-je ?int gethostname(char *hostname, size_t size);

permet de récupérer en argument le nom de la machine locale.

elle renvoie -1 si erreur et 0 en cas de succès.

La primitive gethosbyname

Elle permet d’obtenir une liste d’information sur un hôte. Elle reçoit en argument le nom de l’hôte et

return une structure de données de type hostent contenant des informations sur l’hôte.

struct hostent {

char *h_name;char **h_aliases;

int h_addrtype;

int h_length;

char **h_addr_list;

};

#define h_addr h_addr_list[0]

h_name – le nom official de l’hôte

h_aliases – un tableau de pointeur pointant sur une liste de nom de

l’hôte

h_addrtype – le type de l’adresse de l’hôte; habituellement AF_INET.

h_length – la longueur de l’adresse en octet

h_addr_list – tableau de pointeur pointant les adresses IP de l’hôte

h_addr – la première adresse IP dans h_addr_list.

Gethostbyname revoie un pointeur NULL en cas d’erreur.

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 5/9

5

Exemple d’utilisation :

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <netdb.h>#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>int main(int argc, char *argv[])

{

struct hostent *h;

if (argc != 2) { // error check the command line

fprintf(stderr,"usage: getip address\n");

exit(1);

}

if ((h=gethostbyname(argv[1])) == NULL) { //get the host infoherror("gethostbyname");

exit(1);

}

printf("Host name : %s\n", h->h_name);

printf("IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));

return 0;

}

Exemple d’un serveur TCP concurrent

#include <stdio.h>

#include <stdlib.h>#include <unistd.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <sys/wait.h>

#include <signal.h>

#define MYPORT 3490 // the port users will be connecting to

#define BACKLOG 10 // how many pending connections queue will hold 

void sigchld_handler(int s){

wait(NULL);

}

int main(void)

{

int sockfd, new_fd; // listen on sock_fd, new connection on new_fd

struct sockaddr_in my_addr; // my address information

struct sockaddr_in their_addr; // connector’s address information

int sin_size;

struct sigaction sa;

int yes=1;

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket");

exit(1);

}

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 6/9

6

if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {

perror("setsockopt");

exit(1);

}

my_addr.sin_family = AF_INET; // host byte order

my_addr.sin_port = htons(MYPORT); // short, network byte order

my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

bzero(&(my_addr.sin_zero), 8); // zero the rest of the struct

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))

== -1) {

perror("bind");

exit(1);

}

if (listen(sockfd, BACKLOG) == -1) {

perror("listen");

exit(1);

}

sa.sa_handler = sigchld_handler; // reap all dead processes

sigemptyset(&sa.sa_mask);

sa.sa_flags = SA_RESTART;if (sigaction(SIGCHLD, &sa, NULL) == -1) {

perror("sigaction");

exit(1);

}

while(1) { // main accept() loop

sin_size = sizeof(struct sockaddr_in);

if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,

&sin_size)) == -1) {

perror("accept");

continue;

}

printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));

if (!fork()) { // this is the child process

close(sockfd); // child doesn’t need the listener

if (read(new_fd, "Hello, world!\n", 14, 0) == -1)

perror("send");

close(new_fd);

exit(0);

}

close(new_fd); // parent doesn’t need this

}

return 0;

}

Exemple d’un client TCP simple

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <string.h>

#include <netdb.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/socket.h>#define PORT 3490 // the port client will be connecting to

#define MAXDATASIZE 1024 // max number of bytes we can get at once

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 7/9

7

int main(int argc, char *argv[])

{

int sockfd, numbytes;

char buf[MAXDATASIZE];

struct hostent *he;

struct sockaddr_in their_addr; // connector’s address information

if (argc != 2) {

fprintf(stderr,"usage: client hostname\n");

exit(1);

}

if ((he=gethostbyname(argv[1])) == NULL) { // get the host info

perror("gethostbyname");

exit(1);

}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket");

exit(1);

}

their_addr.sin_family = AF_INET; // host byte order

their_addr.sin_port = htons(PORT); // short, network byte ordertheir_addr.sin_addr = *((struct in_addr *)he->h_addr);

bzero(&(their_addr.sin_zero), 8); // zero the rest of the struct

if (connect(sockfd, (struct sockaddr *)&their_addr,

sizeof(struct sockaddr)) == -1) {

perror("connect");

exit(1);

}

gets(buf);

if ((numbytes=send(sockfd, buf, MAXDATASIZE, 0)) == -1) {

perror("recv");

exit(1);

}buf[numbytes] = ’\0’;

printf("Received: %s",buf);

close(sockfd);

return 0;

}

Exemple d’un serveur UDP

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <errno.h>#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#define MYPORT 4950 // the port users will be connecting to

#define MAXBUFLEN 100int main(void)

{

27

Beej’s Guide to Network Programming

int sockfd;struct sockaddr_in my_addr; // my address information

struct sockaddr_in their_addr; // connector’s address information

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 8/9

8

int addr_len, numbytes;

char buf[MAXBUFLEN];

if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {

perror("socket");

exit(1);

}

my_addr.sin_family = AF_INET; // host byte order

my_addr.sin_port = htons(MYPORT); // short, network byte order

my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP

bzero(&(my_addr.sin_zero), 8); // zero the rest of the struct

if (bind(sockfd, (struct sockaddr *)&my_addr,

sizeof(struct sockaddr)) == -1) {

perror("bind");

exit(1);

}

addr_len = sizeof(struct sockaddr);

if ((numbytes=recvfrom(sockfd,buf,MAXBUFLEN,0,

(struct sockaddr *)&their_addr, &addr_len)) == -1) {

perror("recvfrom");

exit(1);}

printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));

printf("packet is %d bytes long\n",numbytes);

buf[numbytes] = ’\0’;

printf("packet contains \"%s\"\n",buf);

close(sockfd);

return 0;

}

Exemple d’un client UDP

#include <stdio.h>#include <stdlib.h>

#include <unistd.h>

#include <errno.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#define MYPORT 4950 // the port users will be connecting toint main(int argc, char *argv[])

{

int sockfd;

struct sockaddr_in their_addr; // connector’s address information

struct hostent *he;

int numbytes;

if (argc != 3) {

fprintf(stderr,"usage: talker hostname message\n");

exit(1);

}

if ((he=gethostbyname(argv[1])) == NULL) { // get the host info

perror("gethostbyname");

exit(1);

}if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {

perror("socket");

7/27/2019 Les Sockets en C

http://slidepdf.com/reader/full/les-sockets-en-c 9/9

9

exit(1);

}

their_addr.sin_family = AF_INET; // host byte order

their_addr.sin_port = htons(MYPORT); // short, network byte order

their_addr.sin_addr = *((struct in_addr *)he->h_addr);

bzero(&(their_addr.sin_zero), 8); // zero the rest of the struct

if ((numbytes=sendto(sockfd, argv[2], strlen(argv[2]), 0,

(struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1) {

perror("recvfrom");

exit(1);

}

printf("sent %d bytes to %s\n", numbytes,

inet_ntoa(their_addr.sin_addr));

close(sockfd);

return 0;

}