Classe winsock pour newbie

Description

Cette classe permet a tout les debutants en programmation sous Windows de profiter de l'interface reseau que celui-ci propose.

Source / Exemple :


/**** 
 ______________________________
| 							   |
|AUTEUR : IonAce (jean84)      |
|E-MAIL : ionace@latriyade.com |
|______________________________|

Cette classe permet d'initialiser une connexion en TCP ou en UDP, avec choix du 
mode serveur ou du mode client. Elle permet egalement d'envoyer des donnees sur
le reseau et d'en recevoir quelque que soit le protocole utilise. 

Rermeciement à X. & Cosmobob de cppfrance.com pour leurs conseils.

        • /
// Include standard pour utiliser winsock #include <winsock2.h> // On lie la librairie de winsock #pragma comment(lib, "ws2_32.lib") // Creations de nouvelles donnees typedef unsigned int U_INT; // entier non-signe typedef enum MODE_CONNEXION {TCP, UDP}; // pour facilite le choix entre tcp et udp lors de la creation de l'objet typedef enum ERREURS {DISCONNECT, SENDFAILED, GETFAILED, OK, NOTDEFINE}; // pour faciliter la comprehension des erreurs reseaux typedef enum TYPE_SERVICE {SERVER, CLIENT}; // pour faciliter le choix entre serveur et client lors de la creation de l'objet typedef enum TYPE_CONNEXION {TCPCONNECT, UDPCONNECT}; /* TYPE_CONNEXION => Permet a la classe de savoir quelle protocole utilise lors de l'envoi/reception de message. */ class Reseau { protected : // fonctions d'initialisation TCP SOCKET initTcpServeur(U_INT port); SOCKET initTcpClient(char *pip, U_INT port); // fonction d'initialisation UDP SOCKET initUdp(TYPE_SERVICE *pSerCli, char *ip, U_INT port); // variable recevant le handle de la connexion en cours SOCKET s; // structure SOCKADDR_IN SOCKADDR_IN sin; // variable indiquant l'etat des connexions bool initSocket; // variable indiquant le type de connexion TYPE_CONNEXION tpc; public : /* Si serCli vaut true, mode serveur active. Si serCli vaut false, mode client active. Si modeConnexion = true, connexion en TCP sinon connexion en UDP. */ Reseau(MODE_CONNEXION mc, TYPE_SERVICE serCli, char *ip, U_INT port ); // constructeur Reseau(Reseau& r); // constructeur de copie ~Reseau(); // destructeur // Petie fonction permettant de verifier l'etat des connexions. */ bool etatConnexion(); // Fonctions envoyants et recevant des donnees sur le reseau ERREURS envoiBuf(char *pSBuff); ERREURS recevBuf(char *pRBuff, int sizeBuff); }; /* Constructeur */ Reseau::Reseau(MODE_CONNEXION mc, TYPE_SERVICE serCli, char *ip, U_INT port ) { initSocket = false; // si aucune verif n'est bonne, initSocket reste aisni sur false if ( mc == TCP ) // connexion TCP { if ( serCli == SERVER ) // si l'utilisateur a choisie d'utiliser la fonction serveur { s = initTcpServeur(port); if ( s != INVALID_SOCKET ){ // si la connexion est valide initSocket = true; tpc = TCPCONNECT; // on indique que le type de connexion est TCP } } else if ( serCli == CLIENT ) // si l'utilisateur a choisie d'utiliser la fonction client { s = initTcpClient(ip, port); // recuperation du handle de la connexion if ( s != INVALID_SOCKET ){ // si la connexion est valide initSocket = true; tpc = TCPCONNECT; } } } else if ( mc == UDP ) // connexion UDP { s = initUdp(&serCli, ip, port); // initialisation du protocole UDP et recuperation du HANDLE a travers s if ( s != INVALID_SOCKET ) // si s est valide (initialisation reussi) { initSocket = true; tpc = UDPCONNECT; // on indique que le type de connexion est UDP } } } /* Constructeur de copie */ Reseau::Reseau(Reseau& r) { SOCKET nS = r.s; // copie de s SOCKADDR_IN nSin = r.sin; // copie se sin bool nInitSocket = r.initSocket; // copie de initSocket TYPE_CONNEXION nTpc = r.tpc; // copie de tpc (pas super utile mais au moins // tout le ponde dispose de son espace memoire // et y a pas d'ambiguite) } /* Destructeur */ Reseau::~Reseau() { if ( initSocket ) { closesocket(s); WSACleanup(); initSocket = false; } } /* Fonctions membres privees */ SOCKET Reseau::initTcpServeur(U_INT port) { // Initialisation des composants winsock WSAData wsa; WSAStartup(MAKEWORD(2,0), &wsa); // Creation d'une structure SOCKADDR_IN indispensable pour utiliser winsock SOCKADDR_IN cin; /* Declaration des variables de type socket utilise par le serveur. Ces variables representent le HANDLE de la connexion en cours.*/ SOCKET s1; SOCKET s2; // Remplissage de la structure SOCKADDR_IN sin.sin_addr.s_addr = INADDR_ANY; // accepte n'importe quelle IP sin.sin_family = AF_INET; sin.sin_port = htons(port); // Definition du socket s1 = socket(AF_INET,SOCK_STREAM,0); // Remplissage du socket bind(s1,(SOCKADDR*)&sin,sizeof(sin)); // Mise en ecoute du serveur listen(s1,0); int sinsize; int err=0; sinsize=sizeof(cin); while (1) // boucle infinie en attente d'une connexion sur s1 { /* Si une connexion est realise sur le SOCKET s1, alors s2 prend le relai pour toute la suite de la communication et s1 se remet en ecoute.*/ s2 = accept(s1, (SOCKADDR*)&cin, &sinsize); if ( s2 == INVALID_SOCKET ) return INVALID_SOCKET; // Erreur renvoye return s2; } } SOCKET Reseau::initTcpClient(char *pip, U_INT port) { /* Pour toutes les declarations, voir iniTcpServeur(). C'est quasiment identique sauf que l'on n'utilise qu'une srtucture SOCKADDR_IN et qu'une variable de type SOCKET.*/ WSAData wsa; WSAStartup(MAKEWORD(2,0), &wsa); SOCKET s1; // inet_addr() convertie la chaine de caractere en adresse IP valide. sin.sin_addr.s_addr = inet_addr(pip); sin.sin_family = AF_INET; sin.sin_port = htons(port); s1=socket(AF_INET,SOCK_STREAM,0); bind(s1,(SOCKADDR*)&sin,sizeof(sin)); /* La difference avec le serveur et que le client n'attend pas de connexion. Il essaye directement de se connecter et s'il echoue, il renvoie INVALID_SOCKET, au lieu de la connexion en cours, a travers s1. */ int result = connect(s1, (SOCKADDR *)&sin, sizeof(sin)); if ( result ) return INVALID_SOCKET; return s1; } SOCKET Reseau::initUdp(TYPE_SERVICE *pSerCli, char *ip, U_INT port) { WSAData wsa; WSAStartup(MAKEWORD(2,0), &wsa); SOCKET s1; sin.sin_family = AF_INET; // si mode serveur choisi if ( *pSerCli == SERVER ){ sin.sin_addr.s_addr = INADDR_ANY; // instruction pour le serveur } // si mode client choisi else if ( *pSerCli == CLIENT ){ sin.sin_addr.s_addr = inet_addr(ip); // instruction pour le client } sin.sin_port=htons(port); s1 = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); int result = bind(s1,(SOCKADDR*)&sin,sizeof(sin)); if ( result ) return INVALID_SOCKET; // en cas d'erreur /* Contrairement au TCP, l'UDP ne se connecte jamais. C'est pourquoi il n'y a aucune methode pour se connecter dans cette fonction. Une fois cet appel effectue, l'utilisateur n'a plus qu' a se soucier des fonctions envoiBuf() et recvBuf() pour communiquer avec un autre pc. */ return s1; } /* Fonctions membres publiques */ bool Reseau::etatConnexion() { /* Si la connexion est etablie, initSocket vaut true. En cas d'erreur, elle vaudra false. */ return initSocket; } ERREURS Reseau::envoiBuf(char *pSBuff) { if ( initSocket ) // on verifie si la connexion a ete initialise { int accuseEnvoi; if ( tpc == TCPCONNECT ) // si protocole TCP utilise { accuseEnvoi = send(s, pSBuff, strlen(pSBuff), 0); if ( accuseEnvoi == SOCKET_ERROR ) // erreur socket return SENDFAILED; else if ( accuseEnvoi == 0 ) // connexion interrompue return DISCONNECT; else // tout est ok return OK; } else if ( tpc == UDPCONNECT ) // si protocole UDP utilise { accuseEnvoi = sendto(s, pSBuff, strlen(pSBuff), 0, (SOCKADDR *)&sin, sizeof(sin)); if ( accuseEnvoi == SOCKET_ERROR ) // erreur socket return SENDFAILED; else // tout est ok return OK; } } return NOTDEFINE; // si la connexion n'a pas ete initlialise } ERREURS Reseau::recevBuf(char *pRBuff, int sizeBuff) { if ( initSocket ) // on verifie si la connexion a ete initialise { int accuseReception; if ( tpc == TCPCONNECT ) // si protocole TCP utilise { accuseReception = recv(s, pRBuff, (sizeBuff-1), 0); if ( accuseReception == SOCKET_ERROR ){ // erreur lors de la reception return GETFAILED; } else if ( accuseReception == 0 ){ // connexion interrompue return DISCONNECT; } else { pRBuff[accuseReception] = '\0'; return OK; // en cas de reussite, on renvoi OK } } else if ( tpc == UDPCONNECT ) // si protocole UDP utilise { int sinSize = sizeof(sin); accuseReception = recvfrom(s, pRBuff, (sizeBuff-1), 0, (SOCKADDR *)&sin, &sinSize); if ( accuseReception == SOCKET_ERROR ){ return GETFAILED; } else if ( accuseReception == 0 ){ return DISCONNECT; } else { pRBuff[accuseReception] = '\0'; return OK; } } } return NOTDEFINE; // si la connexion n'a pas ete initlialise }

Conclusion :


Compilation sans probleme sous Visual C++ 6.0 et Devcpp (pour les utilisateurs de cet IDE, n'oubliez pas de rajouter -lwsock32 aux options du compilateurs sinon vous aurez des erreurs de types "WSA@... linked error")
Pour ceux qui le desireront, je pourrais mettre a jour la source avec le protocole UDP. Je l'ai volontairement ommis car il faut renvoyer un pointeur de type SOCKADDR en plus du socket et pour les newbies, je trouvais pas ça geniale. Mais n'hesitez pas a me faire part de vos commentaires, je suis loin d'etre un pro donc toutes les suggestions sont bonnes a prendre.

Merci a tous !!
@++ et bon code !

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.