Upload
souleymane-mato
View
215
Download
0
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;
}