|
|
Mode non connecte en C++
par _SebF
1 - Schéma d'une relation
client serveur 2 -
Initialisation de la socket 2.1 -
Commande WSAStartup() 2.2 -
Commande socket()
3 - Ecoute du port UDP
3.1 -
Commande bind()
4 - Echange des données
4.1 - Commande sendto()
4.2 - Commande recvfrom() 5 -
Libération de la socket
5.1 - Commande closesocket()
5.2 - Commande WSACleanup() 6 -
Exemple complet d'une communication client serveur
6.1 - Côté serveur
6.2 - Côté client 7 -
Les liens
8 - Discussion autour de la
documentation
9 -
Suivi du document
Voici le schéma d'une relation entre un client et un serveur.

Une socket est un mécanisme de couche 5 permettant une communication réseau
inter application. En résumé, elle permet la communication entre deux applications
situés sur deux machines distinctes.
Windows se basant sur
Winsock, nous devons initialiser
cette API contrairement à Linux.
Pour cela, nous allons utiliser la fonction WSAStartup(). L'utilisation de cette
fonction est donc obligatoire pour un système d'exploitation Windows. Si vous utilisez un autre OS,
alors passez directement à l'étape suivante.
Voici un exemple d'utilisation pour le côté client
et serveur.
|
//
********************************************************
// Déclaration des variables
// ********************************************************
WSADATA initialisation_win32;
// Variable permettant de récupérer la structure
d'information sur l'initialisation
int
erreur; // Variable permettant de récupérer la valeur
de retour des fonctions utilisées
//
********************************************************
// Initialisation de Winsock
// ********************************************************
erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);
if (erreur!=0)
printf("\nDesole, je ne peux pas initialiser Winsock du a l'erreur
: %d %d",erreur,WSAGetLastError());
else
printf("\nWSAStartup
: OK"); |
- Le premier paramètre indique la version de
Winsock que nous demandons.
- Le second paramètre est l'adresse d'une structure de type WSADATA qui contient toutes les
informations nécessaires résultant de l'initialisation.
- La fonction devra renvoyer 0 pour indiquer que sont exécution c'est
correctement déroulée.
Voici la fiche Msdn concernant la fonction
WSAStartup().
La création d'une socket est obligatoire afin d'obtenir un identifiant unique.
Cela permettra aux prochaines fonctions de toutes ce référencer au même id, donc à la même socket.
Voici un exemple d'utilisation pour le côté client et serveur.
|
//
********************************************************
// Déclaration des variables
// ********************************************************
SOCKET id_de_la_socket;
// Identifiant de la socket
// ********************************************************
// Ouverture d'une Socket
// ********************************************************
id_de_la_socket=socket(AF_INET,SOCK_DGRAM,0);
if
(id_de_la_socket==INVALID_SOCKET)
printf("\nDesole,
je ne peux pas creer la socket du a l'erreur : %d",WSAGetLastError());
else
printf("\nsocket : OK"); |
- Le
premier paramètre indique que vous désirez crée
une socket basé sur le protocole IPv4.
- Le second paramètre sélectionne le
mode connecté via
UDP,
cela nécessitera alors une ouverture de session.
- La fonction retournera l'identifiant de la socket si elle
s'est exécutée correctement. Sinon, elle indiquera la valeur INVALID_SOCKET.
Voici la fiche Msdn concernant la fonction
socket().
La commande bind permet de lier la socket à un port et adresse IP d'écoute.
Voici un exemple d'utilisation pour le côté serveur.
|
//
********************************************************
// Déclaration des variables
// ********************************************************
SOCKADDR_IN information_sur_la_source;
// Déclaration de la structure des informations lié à l'écoute
// ********************************************************
// Lie la socket à une ip et un port d'écoute
// ********************************************************
information_sur_la_source.sin_family=AF_INET;
information_sur_la_source.sin_addr.s_addr=INADDR_ANY;
// Ecoute sur toutes les IP locales
information_sur_la_source.sin_port=htons(33333);
// Ecoute sur le port 33333
erreur=bind(id_de_la_socket,(struct
sockaddr*)&information_sur_la_source,sizeof(information_sur_la_source));
if (erreur!=0)
printf("\nDesole, je ne peux pas ecouter ce port : %d %d",erreur,WSAGetLastError());
else
printf("\nbind : OK"); |
- Le premier argument
est l'identifiant de la socket que vous avez
récupéré grâce à la fonction socket().
- Le second argument est la structure comprenant les informations sur
le port et
l'adresse IP à
se lier.
- Le troisième paramètre spécifie uniquement la taille de la structure du
second.
-
La fonction devra renvoyer 0 pour indiquer que sont exécution c'est correctement
déroulée.
Voici la fiche Msdn concernant la fonction
bind().
La commande sendto permet l'envoi d'une chaîne de caractère à destination du
serveur précisé comme argument de la fonction. Voici un exemple d'utilisation pour le côté
client.
|
//
********************************************************
// Déclaration des variables
// ********************************************************
int
nombre_de_caractere; // Indique le nombre de
caractères qui a été reçu ou envoyé
char buffer[65535];
// Tampon contenant les données reçues ou
envoyées
//
********************************************************
// Envoi des données
// ********************************************************
information_sur_la_destination.sin_family=AF_INET;
// Indiquez l'utilisation d'IPV4
information_sur_la_destination.sin_addr.s_addr=inet_addr("10.10.10.10");
// Indiquez l'adresse IP de votre serveur
information_sur_la_destination.sin_port=htons(33333);
// Port TCP 33333 à destination du serveur
strcpy(buffer,"Coucou, je suis les donnees. www.frameip.com");
// Copie la chaine de caractère dans buffer
nombre_de_caractere=sendto(id_de_la_socket,buffer,strlen(buffer),0,(struct
sockaddr*)&information_sur_la_destination,sizeof(information_sur_la_destination));
if (nombre_de_caractere==SOCKET_ERROR)
printf("\nDesole, je ne peux pas envoyer les
donnees du a l'erreur : %d",WSAGetLastError());
else
printf("\nsend : OK"); |
- Le premier argument
est l'identifiant de la socket que vous avez
récupéré grâce à la fonction socket().
- Le second argument est le buffer contenant les données à
envoyer.
- Le troisième paramètre spécifie uniquement la taille du buffer.
- Le quatrième fait référence à la structure comprenant les
informations sur
le port et
l'adresse IP
de destination.
- Le cinquième indique la taille de la structure précédente.
- La fonction renverra le nombre de caractère qui a
été émis.
Voici la fiche Msdn concernant la fonction
sendto().
La commande recvfrom permet de recueillir dans un buffer les données reçues sur une socket. Voici un exemple d'utilisation pour le côté serveur.
|
//
********************************************************
// Reception des données
// ********************************************************
tempo=sizeof(information_sur_la_source);
// Passe par une variable afin d'utiliser un
pointeur
nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,0,(struct
sockaddr*)&information_sur_la_source,&tempo);
buffer[nombre_de_caractere]=0; // Permet de
fermer le tableau après le contenu des data, car la fonction recvfrom ne
le fait pas
printf("\nVoici les donnees : %s",buffer); |
- Le premier argument
est l'identifiant de la socket que vous avez
récupéré grâce à la fonction accept().
- Le second argument est le buffer contenant les données à
recevoir.
- Le troisième paramètre représente le nombre maximum de
caractère attendu.
- Le quatrième fait référence à la structure comprenant les
informations sur
le port et
l'adresse IP
en écoute.
- Le cinquième indique la taille de la structure précédente.
- La fonction renverra le nombre de caractère qui a
été reçu.
Voici la fiche Msdn concernant la fonction
recvfrom()
Cette fonction permet de libérer proprement l'accès à la socket. Durement
conseillé pour le respect d'un développement propre et d'une utilisation saine
du système d'exploitation.
Voici un exemple d'utilisation pour le côté client et serveur.
|
// ********************************************************
// Fermeture de la socket correspondant à la commande socket()
// ********************************************************
erreur=closesocket(id_de_la_socket);
if
(erreur!=0)
printf("\nDesole, je
ne peux pas liberer la socket du a l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nclosesocket
: OK"); |
- Le premier argument
est l'identifiant de la socket que vous avez récupéré grâce à
la fonction socket().
-
La fonction devra renvoyer 0 pour indiquer que sont exécution c'est correctement
déroulée.
Voici la fiche Msdn concernant la fonction
closesocket().
Cette étape n'est utile et fonctionnelle que dans le cadres du système
d'exploitation Microsoft.
Cette fonction permet de libérer l'accès à
Winsock. Attention, dans un
environnement multiprocess, l'utilisation de cette commande fermera les accès de
tous les process.
Voici un exemple d'utilisation pour le côté client et serveur.
|
// ********************************************************
// Quitte proprement le winsock ouvert avec la commande WSAStartup
// ********************************************************
erreur=WSACleanup(); // A
appeler autant de fois qu'il a été ouvert.
if
(erreur!=0)
printf("\nDesole, je
ne peux pas liberer winsock du a l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSACleanup
: OK"); |
-
La fonction devra renvoyer 0 pour indiquer que sont exécution c'est correctement
déroulée.
Voici la fiche Msdn concernant la fonction
WSACleanup().
Voici un exemple de code fonctionnel qui permet d'écouter sur le
port UDP 33333
et d'afficher les données reçues. Le fichier cpp est disponible
ici.
|
//
********************************************************
// Les includes
// ********************************************************
#include <winsock2.h>
// pour les fonctions socket
#include <cstdio>
// Pour les Sprintf
// ********************************************************
// Les librairies
// ********************************************************
#pragma
comment(lib,"ws2_32.lib")
//
********************************************************
// Définition des variables
// ********************************************************
WSADATA initialisation_win32; //
Variable permettant de récupérer la structure d'information sur
l'initialisation
int erreur;
// Variable permettant de récupérer la valeur
de retour des fonctions utilisées
int tempo;
// Variable temporaire de type int
int nombre_de_caractere;
// Indique le nombre de caractères qui a été
reçu ou envoyé
char buffer[65535];
// Tampon contenant les données reçues ou
envoyées
SOCKET id_de_la_socket; // Identifiant
de la socket
SOCKADDR_IN information_sur_la_source;
// Déclaration de la structure des informations lié à l'écoute
int main (int
argc, char* argv[])
{
printf("\nBonjour, vous etes du cote serveur. www.frameip.com\n");
//
********************************************************
// Initialisation de Winsock
//
********************************************************
erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);
if (erreur!=0)
printf("\nDesole, je ne peux pas initialiser Winsock du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSAStartup : OK");
//
********************************************************
// Ouverture d'une Socket
//
********************************************************
id_de_la_socket=socket(AF_INET,SOCK_DGRAM,0);
if (id_de_la_socket==INVALID_SOCKET)
printf("\nDesole, je ne peux pas creer la socket du a
l'erreur : %d",WSAGetLastError());
else
printf("\nsocket : OK");
//
********************************************************
// Lie la socket à une ip et un
port d'écoute
//
********************************************************
information_sur_la_source.sin_family=AF_INET;
information_sur_la_source.sin_addr.s_addr=INADDR_ANY;
// Ecoute sur toutes les IP locales
information_sur_la_source.sin_port=htons(33333);
// Ecoute sur le port 33333
erreur=bind(id_de_la_socket,(struct
sockaddr*)&information_sur_la_source,sizeof(information_sur_la_source));
if (erreur!=0)
printf("\nDesole, je ne peux pas ecouter ce port : %d
%d",erreur,WSAGetLastError());
else
printf("\nbind : OK");
//
********************************************************
// Reception des données
//
********************************************************
tempo=sizeof(information_sur_la_source);
// Passe par une variable afin d'utiliser un
pointeur
nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,0,(struct
sockaddr*)&information_sur_la_source,&tempo);
buffer[nombre_de_caractere]=0; // Permet
de fermer le tableau après le contenu des data, car la fonction recvfrom
ne le fait pas
printf("\nVoici les donnees : %s",buffer);
//
********************************************************
// Fermeture de la socket
correspondante à la commande socket()
//
********************************************************
erreur=closesocket(id_de_la_socket);
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer la socket du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nclosesocket : OK");
//
********************************************************
// Quitte proprement le winsock
ouvert avec la commande WSAStartup
//
********************************************************
erreur=WSACleanup(); // A appeler
autant de fois qu'il a été ouvert.
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer winsock du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSACleanup : OK");
} |
Voici un exemple de code fonctionnel qui permet d'envoyer des données sur le
port UDP 33333, n'oubliez pas de changer
l'IP de destination pour correspondre à
votre serveur. Le fichier cpp est disponible ici.
|
//
********************************************************
// Les includes
// ********************************************************
#include <winsock2.h>
// pour les fonctions socket
#include <cstdio>
// Pour les Sprintf
// ********************************************************
// Les librairies
// ********************************************************
#pragma
comment(lib,"ws2_32.lib")
//
********************************************************
// Définition des variables
// ********************************************************
WSADATA initialisation_win32; //
Variable permettant de récupérer la structure d'information sur
l'initialisation
int erreur;
// Variable permettant de récupérer la valeur
de retour des fonctions utilisées
int tempo;
// Variable temporaire de type int
int nombre_de_caractere;
// Indique le nombre de caractères qui a été
reçu ou envoyé
char buffer[65535];
// Tampon contennant les données reçues ou
envoyées
SOCKET id_de_la_socket; // Identifiant
de la socket
SOCKADDR_IN information_sur_la_destination;
// Déclaration de la structure des
informations lié au serveur
int main (int
argc, char* argv[])
{
printf("\nBonjour, vous etes du cote client. www.frameip.com\n");
//
********************************************************
// Initialisation de Winsock
//
********************************************************
erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);
if (erreur!=0)
printf("\nDesole, je ne peux pas initialiser Winsock du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSAStartup : OK");
//
********************************************************
// Ouverture d'une Socket
//
********************************************************
id_de_la_socket=socket(AF_INET,SOCK_DGRAM,0);
if (id_de_la_socket==INVALID_SOCKET)
printf("\nDesole, je ne peux pas creer la socket du a
l'erreur : %d",WSAGetLastError());
else
printf("\nsocket : OK");
//
********************************************************
// Envoi des données
//
********************************************************
information_sur_la_destination.sin_family=AF_INET;
// Indiquez l'utilisation d'IPV4
information_sur_la_destination.sin_addr.s_addr=inet_addr("10.10.10.10");
// Indiquez l'adresse IP de votre serveur
information_sur_la_destination.sin_port=htons(33333);
// Port TCP 33333 à destination du serveur
strcpy(buffer,"Coucou, je suis les donnees. www.frameip.com");
// Copie la chaine de caractère dans buffer
nombre_de_caractere=sendto(id_de_la_socket,buffer,strlen(buffer),0,(struct
sockaddr*)&information_sur_la_destination,sizeof(information_sur_la_destination));
if (nombre_de_caractere==SOCKET_ERROR)
printf("\nDesole, je ne peux pas envoyer les donnees du a
l'erreur : %d",WSAGetLastError());
else
printf("\nsend : OK");
//
********************************************************
// Fermeture de la socket
correspondant à la commande socket()
//
********************************************************
erreur=closesocket(id_de_la_socket);
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer la socket du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nclosesocket : OK");
//
********************************************************
// Quitte proprement le winsock
ouvert avec la commande WSAStartup
//
********************************************************
erreur=WSACleanup(); // A appeler
autant de fois qu'il a été ouvert.
if (erreur!=0)
printf("\nDesole, je ne peux pas liberer winsock du a
l'erreur : %d %d",erreur,WSAGetLastError());
else
printf("\nWSACleanup : OK");
} |
-
Liste des fonctions Winsock
-
Liste des structures Winsock
-
Liste des erreurs Winsock
Vous pouvez poser toutes vos questions,
vos remarques et vos expériences à propos de C++ en mode non connecté. Pour cela,
rendez-vous sur le
Forum "Developpement".
Le 04 mars 2004, par _SebF,
publication du document.
Le 02 mars 2004, par _SebF, création du document.
|
|