Les sockets sont des flux de données, permettant à des machines locales ou distantes de communiquer entre elles via des protocoles.
Les différents protocoles sont TCP qui est un protocole dit "connecté", et UDP qui est un protocole dit "non connecté".
Nous allons voir par la suite comment réaliser diverses applications telles qu'un client/serveur TCP
1. 1
Institut supérieur de Génie appliqué
2ème Année Ingénierie
Rapport du mini-projet
I « Socket TCP/IP»
Réaliser par : Encadré par :
M.Oussama Elkhatibi M.Khalid Boukhdir
M.Ibrahim Ben Idriss
M.Lousimi Mouad
Mlle.Ifahir Fatima Zahra
2. 2
Remerciement
Nous saisissons cette occasion pour exprimer nos vifs remerciements
à toute personne ayant contribué à la réalisation de ce travail.
Nous souhaitons tout d'abord remercier nos encadrant M.Boukhdir et
qui nous ont encadrés avec patience durant la réalisation de ce mini-
projet.
3. 3
Table des matières :
Introduction............................................................................................4
1. Cahier des charges............................................................................5
2 Partie théorique :...............................................................................6
Conception :........................................................................................6
2. Partie pratique ................................................................................10
Les fonction utiliser : ........................................................................10
3. Annexe............................................................................................14
Client :...............................................................................................14
Serveur : ............................................................................................16
4. Table de figures..............................................................................18
5. Simulation sur linux .......................................................................19
6. webiographie..................................................................................21
4. 4
Introduction
Les sockets sont des flux de données, permettant à des machines
locales ou distantes de communiquer entre elles via des protocoles.
Les différents protocoles sont TCP qui est un protocole dit connecté,
et UDP qui est un protocole dit non connecté.
Nous allons voir par la suite comment réaliser diverses applications
telles qu'un client/serveur TCP ou même un client/serveur UDP.
Nous passerons aussi sur les sockets asynchrones, ainsi que les
différentes bibliothèques disponibles pour nous faciliter la tâche.
5. 5
1.Cahier des charges
Notre mini-projet consiste a réaliser une socket TCP/IP permettant le client a récupérer un
fichier a partir d’un serveur suivant la procédure qui suit :
Client envoie une requête .
Réponse du serveur : acceptation/refus .
Etablir une connexion entre client-serveur.
Demande de l’information requise .
Envoie de l’information : serveur vers client.
Déconnexion.
6. 6
2Partie théorique :
Conception :
définition
Une socket est un point de communication permettant à un processus d’émettre et de recevoir
des informations. Une socket est identifiée par un entier, elle s’utilise comme un descripteur
de fichier. La communication dans une socket s’effectue dans les deux sens contrairement aux
tubes. En TCP, pour que cette communication puisse avoir lieu il faut que la socket soit
connectée à une autre socket.
Le serveur et le client :
Les serveurs ont une fonction particulière: Ils doivent envoyer des informations pertinentes
aux clients qui en réclament. Comme un serveur ne convient pas d'un rendez-vous avec le
client, il doit rester attentif en permanence pour ne pas risquer de rater une question. Pour ce
faire, on y installe des « daemons“, petits programmes qui tournent en tâche de fond et qui
écoutent continuellement sur un numéro de port donné. Il y a des conventions pour attribuer
ces ports sur des services connus, par exemple le port 80 pour HTTP, le port 110 pour POP3,
le port 21 pour FTP. Il faut qu'il y ait des conventions de ce genre pour que les clients puissent
atteindre ces services.
Lorsque l'on écrit http://62.161.120.45, on ne spécifie pas de port; sous-entendu, il s'agit du
port 80 parce que l'on invoque un service HTTP. Il serait possible d'écrire:
7. 7
http://62.161.120.45:80 Ici, on spécifie le port. Certaines protections triviales consistent
justement à forcer un service à ne pas employer le port standard. Un administrateur pourrait
décider de mettre son serveur HTTP à l'écoute du port 88. Dans ce cas, si l'utilisateur n'est pas
au courant de cette particularité, il ne pourra pas accéder à ce serveur (sauf s'il dispose d'un
scanner de ports et qu'il découvre la supercherie).
Figure 1
En revanche, le client qui émet la requête ne dispose pas de port d'écoute attitré. Ce n'est pas
un serveur, c'est un client; il n'a donc rien à écouter d'autre que les réponses à ses questions. Il
faut donc, lorsqu'il envoie sa requête, qu'il spécifie sur quel port il va écouter la réponse, de
manière à ce que le serveur puisse construire un socket efficace pour ladite réponse.
Vous êtes-vous demandé par quel miracle, si vous ouvrez deux fois votre navigateur pour
afficher deux pages différentes sur le même serveur, les informations ne se mélangent pas?
C'est parce que les deux sessions du navigateur indiquent des ports de réponse différents!
C'est le NOS du client qui choisit les ports de réponse en fonction de ceux qui sont
disponibles sur la machine.
8. 8
Figure 2
Types :
Socket internet: Les sockets du domaine Internet sont utilisés pour la communication
bidirectionnelle entre des processus qui sont sur des machines différentes d'un réseau IP.
Ainsi, un socket du domaine Internet désignent un des nœuds d'un flux de données à travers
un réseau IP tel qu'Internet.
Dans ce type de socket, une adresse socket est la combinaison d'une adresse IP et d'un port
(lequel est associé à un processus) formant une seule et unique entité.
Un socket Internet se caractérise par la combinaison des éléments suivants :
-Adresse du socket local : adresse IP locale et numéro de port.
-Adresse du socket distant : uniquement pour les sockets TCP déjà établis.
-Protocole : un protocole de la couche transport (TCP, UDP).
Socket unix : Les sockets du domaine UNIX utilisent le système de fichiers comme espace de
noms. Ils sont référencés dans le système de fichier par les processus en tant qu'inodes. Cela
permet à deux processus d'ouvrir le même socket pour communiquer. Toutefois, la
communication se produit entièrement dans le noyau du système d'exploitation.
9. 9
Il est possible d'utiliser les permissions du système de fichiers pour contrôler l'accès aux
sockets IPC. On peut définir quel processus peut se connecter à tel autre de cette manière.
En plus d'envoyer des données, ces processus peuvent envoyer des descripteurs de fichiers sur
un socket du domaine Unix, en utilisant les fonctions d'appel système « sendmsg » et «
recvmsg ».
Socket raw : Les sockets raw reçoivent les paquets bruts avec leur en-tête, et elles n'ajoutent
automatiquement un en-tête lorsque l'on envoie les paquets que si on le demande dans une
option de la socket. Une utilisation possible des sockets raw est de développer de nouveaux
protocoles de couche transport en espace utilisateur7.
Les sockets raw sont nécessaires aux protocoles qui sont directement encapsulés dans IP, sans
passer par TCP ni UDP. On peut par exemple citer le protocole de gestion de groupes de
multidiffusion IGMP, le protocole de routage dynamique OSPF, ainsi que le protocole ICMP
utilisé par la commande ping8.
Enfin, on peut s'en servir pour créer des paquets TCP ou UDP inhabituels. En particulier, un
pirate informatique pourra contrefaire des paquets dans l'intention de nuire ou de s'introduire
dans un système
10. 10
2.Partie pratique
Les fonction utiliser :
Nous avons utiliser plusieurs fonction sous linux, c'est un peu différent puisque les fichiers à
inclure ne sont pas les mêmes. Pour combler l'écart entre Windows et Linux, nous utiliserons
des définitions et des typedef.
Commençons par inclure les fichiers nécessaires :
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
Pour pouvoir utiliser pleinement les sockets, Tout d'abord, nous allons créer une socket pour
pouvoir configurer la connexion qu'elle va établir. Ensuite, nous allons la paramétrer pour
communiquer avec le client. Enfin, nous allons fermer la connexion précédemment établie.
Créer une socket
Pour utiliser une socket, il va nous falloir le déclarer avec le type SOCKET :
SOCKET sock;
Pour la créer, il nous faudra utiliser la fonction socket avec le prototype suivant :
int socket(int domain, int type, int protocol);
La fonction retourne une socket créée à partir des paramètres qui suivent.
Le paramètre domain représente la famille de protocoles utilisée. Il prend la valeur AF_INET
pour le protocole TCP/IP .Sinon, il prend la valeur AF_UNIX pour les communications UNIX
en local sur une même machine.
Le type indique le type de service, il peut avoir les valeurs suivantes :
SOCK_STREAM, si on utilise le protocole TCP/IP.
11. 11
Dans le cas de la suite TCP/IP, le paramètre protocol n'est pas utile, on le mettra ainsi toujours
à 0.Comme dans notre cas nous utiliserons le protocole TCP/IP, notre fonction sera toujours :
sock = socket(AF_INET, SOCK_STREAM, 0);
Après avoir déclaré et créé la socket, nous allons la paramétrer. Pour cela, nous allons
déclarer une structure de type SOCKADDR_IN qui va nous permettre de configurer la
connexion. On l'appelle contexte d'adressage. Cette structure est définie de la façon suivante :
struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin.sin_addr.s_addr sera l'IP donnée automatiquement au serveur. Pour le connaître nous
utiliserons la fonction htonl avec comme seul paramètre la valeur INADDR_ANY.
Si vous voulez spécifier une adresse IP précise à utiliser, il est possible d'utiliser la fonction
inet_addr avec comme seul paramètre l'IP dans une chaine de caractères :
inet_addr("127.0.0.1");
sin.sin_family sera toujours égal à AF_INET dans notre cas (en savoir plus).
Et sin.sin_port sera égal à la valeur retournée par la fonction htons, avec comme paramètre le
port utilisé.
Le champ sin_zero ne sera pas utilisé.
Nous allons la déclarer et l'initialiser comme ceci :
SOCKADDR_IN sin;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(23);
12. 12
Établir une connexion avec le client :
Enfin, pour associer à la socket ces informations, nous allons utiliser la fonction :
int bind(int socket, const struct sockaddr* addr, socklen_t addrlen);
La fonction retourne SOCKET_ERROR en cas d'erreur (en savoir plus).
Le paramètre socket désigne la socket du serveur avec laquelle on va associer les
informations.
Le paramètre addr est un pointeur de structure sockaddr du serveur.
Il spécifie l'IP à laquelle on se connecte... Comme la fonction a besoin d'un pointeur sur
structure sockaddr, et que nous disposons que d'une structure SOCKADDR_IN, nous allons
faire un cast, pour éviter que le compilateur nous retourne une erreur lors de la compilation.
bind(sock, (SOCKADDR*)&sin, sizeof(sin));
Voilà ! Maintenant que toutes les informations sont données, il va falloir mettre la socket dans
un état d'écoute (établir la connexion, si vous préférez :p ).
Pour cela, nous allons utiliser la fonction listen. Voici son prototype:
int listen(int socket, int backlog);
Le paramètre socket désigne la socket qui va être utilisée.
Le paramètre backlog représente le nombre maximal de connexions pouvant être mises en
attente.
Nous utiliserons donc notre fonction ainsi :
listen(sock, 5);
En général, on met le nombre maximal de connexions pouvant être mises en attente à 5
(comme les clients FTP).
Enfin, on termine avec la fonction accept avec le prototype suivant :
int accept(int socket, struct sockaddr* addr, socklen_t* addrlen);
13. 13
Cette fonction permet la connexion entre le client et le serveur en acceptant un appel de
connexion.
La fonction retourne la valeur INVALID_SOCKET en cas d'échec. Sinon, elle retourne la
socket du client.
Le paramètre socket est, comme dans les autre fonctions, la socket serveur utilisée.
Le paramètre addr est un pointeur sur le contexte d'adressage du client.
Le paramètre addrlen ne s'utilise pas comme dans la fonction bind ; ici, il faut créer une
variable taille de type socklen_t (qui n'est rien d'autre qu'un entier), égale à la taille du
contexte d'adressage du client. Ensuite, il faudra passer l'adresse de cette variable en
paramètre.
On utilisera donc la fonction comme cela :
socklen_t taille = sizeof(csin);
csock = accept(sock, (SOCKADDR*)&csin, &taille);
Fermeture de connexion :
Finalement nous terminerons par la fonction closesocket qui permet de fermer une socket.
int closesocket(int sock);
14. 14
3.Annexe
Client :
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
int main(){
FILE *fp;
int csd,n,ser,s,cli,cport,newsd;
char name[100],rcvmsg[100],rcvg[100],fname[100];
struct sockaddr_in servaddr;
printf("Enter the port");
scanf("%d",&cport);
csd=socket(AF_INET,SOCK_STREAM,0);
if(csd<0){
printf("Error....n");
exit(0);}
else
printf("Socket is createdn");
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(cport);
if(connect(csd,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)
printf("Error in connectionn");
else
15. 15
printf("connectedn");
printf("Enter the existing file namet");
scanf("%s",name);
printf("Enter the new file namet");
scanf("%s",fname);
fp=fopen(fname,"w");
send(csd,name,sizeof(name),0);
while(1){
s=recv(csd,rcvg,100,0);
rcvg[s]='0';
if(strcmp(rcvg,"error")==0)
printf("File is not availablen");
if(strcmp(rcvg,"completed")==0){
printf("File is transferred........n");
fclose(fp);
close(csd);
break;}
else
fputs(rcvg,stdout);
fprintf(fp,"%s",rcvg);}}
16. 16
Serveur :
#include<stdio.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include<stdlib.h>
int main(){
FILE *fp;
int sd,newsd,ser,n,a,cli,pid,bd,port,clilen;
char name[100],fileread[100],fname[100],ch,file[100],rcv[100];
struct sockaddr_in servaddr,cliaddr;
printf("Enter the port addressn");
scanf("%d",&port);
sd=socket(AF_INET,SOCK_STREAM,0);
if(sd<0)
printf("Cant createn");
else
printf("Socket is createdn");
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(port);
a=sizeof(servaddr);
bd=bind(sd,(struct sockaddr *)&servaddr,a);
if(bd<0)
printf("Cant bindn");
else