Bibliothèque permettant d'utiliser les sockets de manière transparente qu'elles soient windows / unix et tcp / udp

Description

Ce code c++ sans class permet d'utiliser des sockets compatibles Windows et UNIX. Sans avoir à ce soucier des différences de programmation entre une socket TCP et UDP.

J'ai réaliser cette "bibliothèque" car je programme des sockets Windows et UNIX, TCP et UDP, et j'en avais marre d'avoir à changer le code à chaque fois, un simple #include "socket.hpp" et #define TCP ou UDP suffit maintenant. Un gain de temps et une portabilité non négligeable.

Sous windows ne pas oublier de linker avec "libwsock32.a"

N'hésitez pas à laisser des commentaires pour que je puisse améliorer mon code !

Source / Exemple :


/*-------------SOCKET.HPP-------------*/
// Socket library -*- C++ -*-

// Copyright (C) 2006 Christophe Tournayre
//
// This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2, or
// (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.

#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__

// ********************************************************
// Les includes
// ********************************************************
#if defined(WIN32)
    #include <winsock2.h> // pour les fonctions socket
#else
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <linux/socket.h>
#endif

#include <string>
#include <iostream> //Pour cout, cin, cerr

// ********************************************************
// Déclaration des structures et ENUM
// ********************************************************

enum Type {Udp, Tcp};

// Structure pour l'inforamtion de la socket
typedef struct
{
    SOCKET id;          // Déclaration de l'identifiant e la socket
    SOCKADDR_IN server; // Déclaration de la structure des informations lié au serveur
} Sock;

// Structure pour la fonction Recv (nb contient le nb de charactere recus, et c le charactere recu)
typedef struct
{
    int nb;             // Nombre d'octets recus
    char c;           // Charactere recu
} Recv;

Sock connect(char* address, int port, Type type);
int send(Sock info, std::string mess, Type type);
Recv recv(Sock info, Type type);
int disconnect(Sock info, Type type);

#endif

/*-------------SOCKET.CPP-------------*/

// Socket library -*- C++ -*-

// Copyright (C) 2006 Christophe Tournayre
//
// This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2, or
// (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.

#include "socket.hpp"

using namespace std;

Sock connect(char* address, int port, Type type)
{
    // ********************************************************
    // Déclaration des variables
    // ********************************************************
    #if defined(WIN32)
        WSADATA initialisation_win32; // Variable permettant de récupérer la structure d'information sur l'initialisation
    #endif

    Sock info;
    int erreur=0, nb; // Variable permettant de récupérer la valeur de retour des fonctions utilisées
    string buffer; // Tampon contenant les données a envoyer

    #if defined(WIN32)
    // ********************************************************
    // Initialisation de Winsock
    // ********************************************************
    erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);

    if (erreur!=0)
    {
        cerr << "Desole, je ne peux pas initialiser Winsock du a l'erreur : "<< erreur << " " << WSAGetLastError() << endl;
        throw(1);
    }
    else
        cout <<"WSAStartup                    : OK" << endl;
    #endif

    // ********************************************************
    // Ouverture d'une Socket
    // ********************************************************
    if(type==Tcp)
        info.id=socket(AF_INET,SOCK_STREAM,0);

    else
        info.id=socket(AF_INET,SOCK_DGRAM,0);

    if (info.id==INVALID_SOCKET)
    {
        cerr << "Desole, je ne peux pas creer la socket du a l'erreur : " << WSAGetLastError() << endl;
        throw(2);
    }
    else
        cout << "socket                        : OK" << endl;

    // ********************************************************
    // Ouverture de la session
    // ********************************************************
    info.server.sin_family=AF_INET;
    info.server.sin_addr.s_addr=inet_addr(address); // @ip serveur
    info.server.sin_port=htons(port); // Port écouté du serveur

    if(type==Tcp)
    {
        cout <<"connection en cours           ";

        erreur=connect(info.id,(struct sockaddr*)&info.server,sizeof(info.server));

        if (erreur!=0)
        {
            cerr <<"Desole, je n'ai pas pu ouvrir la session TCP : " << erreur << " " << WSAGetLastError() << endl;
            throw(3);
        }
        else
            cout <<": OK" << endl;
    }

    return info;
}

int send(Sock info, string mess, Type type)
{
    // ********************************************************
    // Déclaration des variables
    // ********************************************************
    int nb;

    // ********************************************************
    // Envoi des données
    // ********************************************************
    if (mess.size()>65535)
    {
        cerr << "Message trop long!" << endl;
        return -1;
    }

    if(type==Tcp)
        nb=send(info.id,mess.c_str(),mess.size(),0);
    else
        nb=sendto(info.id,mess.c_str(),mess.size(),0,(struct sockaddr*)&info.server,sizeof(info.server));

    if (nb==SOCKET_ERROR)
    {
        cerr << "Desole, je n'ai pas pu envoyer les donnees du a l'erreur : " << WSAGetLastError() << endl;
        return -2;
    }
    else
    {
        cout << "Requete HTTP                  : OK" << endl;
        return 0;
    }
}

Recv recv(Sock info, Type type)
{
    Recv ret;

    if(type==Udp)
    {
        int temp=sizeof(info.server); // Passe par une variable afin d'utiliser un pointeur
        ret.nb=recvfrom(info.id,&ret.c,1,0,(struct sockaddr*)&info.server,&temp);
    }
    else
        ret.nb=recv(info.id,&ret.c,1,0);

    return ret;
}

int disconnect(Sock info, Type type)
{
    // ********************************************************
    // Déclaration des variables
    // ********************************************************
    int erreur=0, ret=0;

    if(type==Tcp)
    {
        // ********************************************************
        // Fermeture de la session TCP Correspondant à la commande connect()
        // ********************************************************
        erreur=shutdown(info.id,2);

        if (erreur!=0)
        {
            cerr << "Desole, je ne peux pas fermer la session TCP du a l'erreur : " << erreur << " " << WSAGetLastError() << endl;
            ret = -1;
        }
        else
            cerr << "shutdown                      : OK" << endl;
    }

    // ********************************************************
    // Fermeture de la socket correspondant à la commande socket()
    // ********************************************************
    #if defined(WIN32)
        erreur=closesocket(info.id);
    #else
        erreur=close(info.id);
    #endif

    if (erreur!=0)
    {
        cerr << "Desole, je ne peux pas liberer la socket du a l'erreur : " << erreur << " " << WSAGetLastError() << endl;
        ret = -2;
    }
    else
        cout << "closesocket                   : OK" << endl;

    #if defined(WIN32)
        // ********************************************************
        // Quitte le winsock ouvert avec la commande WSAStartup
        // ********************************************************
        erreur=WSACleanup();

        if (erreur!=0)
        {
            cerr << "Desole, je ne peux pas liberer winsock du a l'erreur : " << erreur << " " <<WSAGetLastError() << endl;
            ret= -3;
        }
        else
            cout << "WSACleanup                    : OK" << endl;
    #endif

    return ret;
}

/*--------------MAIN.CPP--------------*/

// Exemple d'utilisation de la bibliothèque

#include <string>
#include <iostream>
#include "socket.hpp"

using namespace std;

int main ()
{
    Sock info;
    Recv ret;
    int i = 0, val = 1024;
    string s, req("Donnees a envoyer");
    
    try
    {
        info=connect("172.0.0.1", 6666, Tcp);
    }   
        catch (int tmp)   // Traitement de l'exception
    {
        cerr << "Erreur dans la connexion" << endl;
        return tmp;
    }
    

    if(send(info, req, Tcp) !=0)
    {
        cerr << "Erreur lors de l'envoi de la requete : " << req << endl;
        disconnect(info, Tcp);
        return -4;
    }

    ret.nb=1;

    while(ret.nb>0 && i<=val)
    {
        ret=recv(info,Tcp);

        if (ret.nb==SOCKET_ERROR)
        {
            cerr << "ERREUR : Aucune données recue" << endl;
            disconnect(info, Tcp);
            retour= -2;
        }

        i++;
        s+=ret.c
    }
    
    cout << "Message recu :" << s << endl;

    if (disconnect(info, Tcp) != 0)
    {
        cerr << "Erreur lors de la deconnection !";
        return -3;
    }
    
    return 0;
}

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.