Accueil > > > ENCAPSULATION D'UNE PARTIE DE L'API SOCKET PORTABLE
ENCAPSULATION D'UNE PARTIE DE L'API SOCKET PORTABLE
Information sur la source
Description
voila, ceci est une tentative d'encapsulation dans des classes d'une partie des api sockets. ce code nécéssite une partie de boost : boost::noncopyable (www.boost.org) qui empeche la copie d'une instance d'un objet.
Source
- #ifndef sock_h
- #define sock_h
-
- #include <boost/utility.hpp>
- #include <string>
-
- #ifdef WIN32
- #include <winsock.h>
- #define wsastart(); {WSADATA WsaData; WSAStartup(MAKEWORD(1,1), &WsaData);}
- #define wsaclean(); WSACleanup();
- #pragma comment(lib, "ws2_32.lib")
- #else
- #define wsastart();
- #define wsaclean();
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <sys/types.h>
- #define SOCKET_ERROR (-1) /* défini dans winsock.h */
- typedef int SOCKET;
- #define INVALID_SOCKET (SOCKET)(~0) /* défini dans winsock.h */
- #define closesocket close
- #endif
-
- struct socket_error : std::exception {};
-
- struct base_sock : boost::noncopyable
- {
- struct address
- {
- protected:
- std::string _name;
- unsigned short _port;
-
- public:
- address(const address & other)
- : _name(other._name), _port(other._port)
- {
- }
-
- address(const std::string & __name, const unsigned short & __port)
- : _name(__name), _port(__port)
- {
- }
-
- address(const std::string & __name)
- : _name(__name), _port(0)
- {
- }
-
- address(const unsigned short & __port)
- : _port(__port)
- {
- }
-
- address()
- : _port(0)
- {
- }
-
- address & operator = (const address & other)
- {
- _name = other._name;
- _port = other._port;
- return *this;
- }
-
- void clear()
- {
- _name = "";
- _port = 0;
- }
-
- bool is_empty() const
- {
- return _name == "" && _port == 0;
- }
-
- const unsigned short & port() const
- {
- return _port;
- }
-
- const std::string & name() const
- {
- return _name;
- }
-
- unsigned short & set_port(const unsigned short & port)
- {
- return _port = port;
- }
-
- std::string & set_name(const std::string & name)
- {
- return _name = name;
- }
-
- bool operator == (const address & other) const
- {
- return (_name == other._name) && (_port == other._port);
- }
- };
-
- protected:
- address sock_address;
- SOCKET s;
-
- private:
- void create()
- {
- close();
- s = socket(AF_INET, SOCK_STREAM, 0);
- if(s == INVALID_SOCKET) throw socket_error();
- }
-
- public:
-
- base_sock()
- : s(INVALID_SOCKET)
- {
- wsastart();
- }
-
- virtual ~base_sock()
- {
- close();
- wsaclean();
- }
-
- bool good() const
- {
- return s != INVALID_SOCKET;
- }
-
- virtual void write(const std::string & data) const
- {
- if(!good()) throw socket_error();
- if(::send(s, data.data(), (int)data.size(), 0) == SOCKET_ERROR) throw socket_error();
- }
-
- virtual std::string read() const
- {
- if(!good()) throw socket_error();
-
- // on crée un buf avec la taille max de data qu'il peut recevoir
- unsigned long cbdata;
- int cbopt = sizeof(cbdata);
- if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&(cbdata), &cbopt) == SOCKET_ERROR) throw socket_error();
- char* data = new char[cbdata];
-
- // on recoit
- int len;
- if((len = recv(s, data, cbdata, 0)) == SOCKET_ERROR)
- {
- delete[] data;
- throw socket_error();
- } else {
- std::string ret(data, len);
- delete[] data;
- return ret;
- }
- }
-
- void close()
- {
- if(!good()) return;
- ::closesocket(s);
- sock_address.clear();
- s = INVALID_SOCKET;
- }
-
- void listen(const address & addr)
- {
- create();
-
- sockaddr_in sain;
- sain.sin_family = AF_INET;
- sain.sin_port = ::htons(addr.port());
-
- if(addr.name() == "")
- sain.sin_addr.s_addr = INADDR_ANY;
- else
- {
- hostent* host = ::gethostbyname(addr.name().c_str());
- if(host == NULL) throw socket_error();
- memcpy((void*)&sain.sin_addr, (void*)host->h_addr, 4);
- }
-
- if(::bind(s, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) throw socket_error();
- sock_address = addr;
-
- if(::listen(s, SOMAXCONN) == SOCKET_ERROR) throw socket_error();
- }
-
- void accept(const base_sock & listen_sock)
- {
- if(!listen_sock.good()) throw socket_error();
-
- create();
-
- sockaddr_in addr;
- int len = sizeof(sockaddr_in);
- s = ::accept(listen_sock.s, (sockaddr*)&addr, &len);
- if(s == INVALID_SOCKET) throw socket_error();
-
- sock_address.set_port(addr.sin_port);
- sock_address.set_name(inet_ntoa(addr.sin_addr));
- }
-
- void connect(const address & addr)
- {
- create();
-
- sockaddr_in sain;
- int len = sizeof(sockaddr_in);
- sain.sin_family = AF_INET;
- sain.sin_port = ::htons(addr.port());
-
- hostent* host = ::gethostbyname(addr.name().c_str());
- if(host == NULL) throw socket_error();
- memcpy((void*)&sain.sin_addr, (void*)host->h_addr, 4);
-
- if(::connect(s, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) throw socket_error();
- sock_address = addr;
- }
-
- const address & get_address()
- {
- return sock_address;
- }
-
- class sock_set : boost::noncopyable
- {
- // initialisation d'une instance nulle
- sock_set(const bool & is_null)
- : bnull(is_null)
- {
- }
-
- protected:
- fd_set fds;
- bool bnull;
-
- public:
-
- // renvoit un sock_set nul
- static sock_set & null()
- {
- static sock_set ret(true);
- return ret;
- }
-
- sock_set()
- : bnull(false)
- {
- FD_ZERO(&fds);
- }
-
- inline void add(const base_sock & _s)
- {
- if(bnull) throw socket_error();
- if(!_s.good()) throw socket_error();
- FD_SET(_s.s, &fds);
- }
-
- inline void del(const base_sock & _s)
- {
- if(bnull) throw socket_error();
- if(!_s.good()) throw socket_error();
- FD_CLR(_s.s, &fds);
- }
-
- inline bool is_set(const base_sock & _s) const
- {
- if(bnull) throw socket_error();
- if(!_s.good()) throw socket_error();
- return FD_ISSET(_s.s, &fds) != 0;
- }
-
- static int select(sock_set & read_set, sock_set & write_set, sock_set & error_set, const timeval & timeout)
- {
- if(read_set.bnull && write_set.bnull && error_set.bnull) throw socket_error();
-
- fd_set * r = read_set.bnull ? NULL : &(read_set.fds);
- fd_set * w = write_set.bnull ? NULL : &(write_set.fds);
- fd_set * e = error_set.bnull ? NULL : &(error_set.fds);
-
- int ret = ::select(0, r, w, e, &timeout);
- if(ret == SOCKET_ERROR) throw socket_error();
- return ret;
- }
-
- };
- };
-
- #endif
#ifndef sock_h
#define sock_h
#include <boost/utility.hpp>
#include <string>
#ifdef WIN32
#include <winsock.h>
#define wsastart(); {WSADATA WsaData; WSAStartup(MAKEWORD(1,1), &WsaData);}
#define wsaclean(); WSACleanup();
#pragma comment(lib, "ws2_32.lib")
#else
#define wsastart();
#define wsaclean();
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#define SOCKET_ERROR (-1) /* défini dans winsock.h */
typedef int SOCKET;
#define INVALID_SOCKET (SOCKET)(~0) /* défini dans winsock.h */
#define closesocket close
#endif
struct socket_error : std::exception {};
struct base_sock : boost::noncopyable
{
struct address
{
protected:
std::string _name;
unsigned short _port;
public:
address(const address & other)
: _name(other._name), _port(other._port)
{
}
address(const std::string & __name, const unsigned short & __port)
: _name(__name), _port(__port)
{
}
address(const std::string & __name)
: _name(__name), _port(0)
{
}
address(const unsigned short & __port)
: _port(__port)
{
}
address()
: _port(0)
{
}
address & operator = (const address & other)
{
_name = other._name;
_port = other._port;
return *this;
}
void clear()
{
_name = "";
_port = 0;
}
bool is_empty() const
{
return _name == "" && _port == 0;
}
const unsigned short & port() const
{
return _port;
}
const std::string & name() const
{
return _name;
}
unsigned short & set_port(const unsigned short & port)
{
return _port = port;
}
std::string & set_name(const std::string & name)
{
return _name = name;
}
bool operator == (const address & other) const
{
return (_name == other._name) && (_port == other._port);
}
};
protected:
address sock_address;
SOCKET s;
private:
void create()
{
close();
s = socket(AF_INET, SOCK_STREAM, 0);
if(s == INVALID_SOCKET) throw socket_error();
}
public:
base_sock()
: s(INVALID_SOCKET)
{
wsastart();
}
virtual ~base_sock()
{
close();
wsaclean();
}
bool good() const
{
return s != INVALID_SOCKET;
}
virtual void write(const std::string & data) const
{
if(!good()) throw socket_error();
if(::send(s, data.data(), (int)data.size(), 0) == SOCKET_ERROR) throw socket_error();
}
virtual std::string read() const
{
if(!good()) throw socket_error();
// on crée un buf avec la taille max de data qu'il peut recevoir
unsigned long cbdata;
int cbopt = sizeof(cbdata);
if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&(cbdata), &cbopt) == SOCKET_ERROR) throw socket_error();
char* data = new char[cbdata];
// on recoit
int len;
if((len = recv(s, data, cbdata, 0)) == SOCKET_ERROR)
{
delete[] data;
throw socket_error();
} else {
std::string ret(data, len);
delete[] data;
return ret;
}
}
void close()
{
if(!good()) return;
::closesocket(s);
sock_address.clear();
s = INVALID_SOCKET;
}
void listen(const address & addr)
{
create();
sockaddr_in sain;
sain.sin_family = AF_INET;
sain.sin_port = ::htons(addr.port());
if(addr.name() == "")
sain.sin_addr.s_addr = INADDR_ANY;
else
{
hostent* host = ::gethostbyname(addr.name().c_str());
if(host == NULL) throw socket_error();
memcpy((void*)&sain.sin_addr, (void*)host->h_addr, 4);
}
if(::bind(s, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) throw socket_error();
sock_address = addr;
if(::listen(s, SOMAXCONN) == SOCKET_ERROR) throw socket_error();
}
void accept(const base_sock & listen_sock)
{
if(!listen_sock.good()) throw socket_error();
create();
sockaddr_in addr;
int len = sizeof(sockaddr_in);
s = ::accept(listen_sock.s, (sockaddr*)&addr, &len);
if(s == INVALID_SOCKET) throw socket_error();
sock_address.set_port(addr.sin_port);
sock_address.set_name(inet_ntoa(addr.sin_addr));
}
void connect(const address & addr)
{
create();
sockaddr_in sain;
int len = sizeof(sockaddr_in);
sain.sin_family = AF_INET;
sain.sin_port = ::htons(addr.port());
hostent* host = ::gethostbyname(addr.name().c_str());
if(host == NULL) throw socket_error();
memcpy((void*)&sain.sin_addr, (void*)host->h_addr, 4);
if(::connect(s, (struct sockaddr *) &sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR) throw socket_error();
sock_address = addr;
}
const address & get_address()
{
return sock_address;
}
class sock_set : boost::noncopyable
{
// initialisation d'une instance nulle
sock_set(const bool & is_null)
: bnull(is_null)
{
}
protected:
fd_set fds;
bool bnull;
public:
// renvoit un sock_set nul
static sock_set & null()
{
static sock_set ret(true);
return ret;
}
sock_set()
: bnull(false)
{
FD_ZERO(&fds);
}
inline void add(const base_sock & _s)
{
if(bnull) throw socket_error();
if(!_s.good()) throw socket_error();
FD_SET(_s.s, &fds);
}
inline void del(const base_sock & _s)
{
if(bnull) throw socket_error();
if(!_s.good()) throw socket_error();
FD_CLR(_s.s, &fds);
}
inline bool is_set(const base_sock & _s) const
{
if(bnull) throw socket_error();
if(!_s.good()) throw socket_error();
return FD_ISSET(_s.s, &fds) != 0;
}
static int select(sock_set & read_set, sock_set & write_set, sock_set & error_set, const timeval & timeout)
{
if(read_set.bnull && write_set.bnull && error_set.bnull) throw socket_error();
fd_set * r = read_set.bnull ? NULL : &(read_set.fds);
fd_set * w = write_set.bnull ? NULL : &(write_set.fds);
fd_set * e = error_set.bnull ? NULL : &(error_set.fds);
int ret = ::select(0, r, w, e, &timeout);
if(ret == SOCKET_ERROR) throw socket_error();
return ret;
}
};
};
#endif
Conclusion
je l'ai testé sous windows (vc++7) ca a l'air de bien fonctionner. normalement il devrait compiler/fonctionner sous linux, si qq1 pouvait tester (je n'en ai plus sous la main)
j'essaierais rapidement de dériver base_sock pour supporter la cryptographie, et pour respecter l'interface des i/o streams standards du c++, ainsi que d'améliorer la gestion d'erreur.
merci de me signaler tout bug, suggestion ou demande d'explication :)
14/01 : maj
correction de 2-3 petites fautes petites modifications pour faciliter la dérivation suppression de la lourdeur d'utilisation du template select par la mise en place d'un sock_set null
Sources du même auteur
Sources de la même categorie
Commentaires et avis
|
Derniers Blogs
ARTICLE DANS PROGRAMMEZ SUR LES PRINCIPES SOLIDARTICLE DANS PROGRAMMEZ SUR LES PRINCIPES SOLID par fathi
Hello tout le monde! J'ai pas pu blogger ces derniers temps car j'ai eu un (heureux) petit chamboulement dans ma vie perso (un "bug" de 3.8 kg et de 52 cm) J'en profite juste pour vous annoncer la parution d'un article sur les principes SOLID ...
Cliquez pour lire la suite de l'article par fathi PARUTION DE MON LIVRE SUR WPF 4PARUTION DE MON LIVRE SUR WPF 4 par odewit
La 2e édition de mon livre sur WPF sort aujourd'hui en version numérique et lundi en version papier :-)
L'ouvrage présente de façon approfondie les fonctionnalités de WPF 4 : graphisme 2D et 3D, animation, multimédia, interfaces utilisateur, databind...
Cliquez pour lire la suite de l'article par odewit EDM : COMMENT UTILISER L'HORIZONTAL ENTITY SPLITTINGEDM : COMMENT UTILISER L'HORIZONTAL ENTITY SPLITTING par Matthieu MEZIL
Une des raisons pour lesquelles j'adore l'Entity Framework est la puissance de son mapping. Beaucoup de développeurs pour ne pas dire la plus part n'en n'ont pas conscience. Pour rappel, j'ai réalisé des videos (en anglais) sur le mapping . Certains scena...
Cliquez pour lire la suite de l'article par Matthieu MEZIL [WP7DEV][REACTIVE] RENDRE LES REACTIVE EXTENSIONS PLUS STABLES[WP7DEV][REACTIVE] RENDRE LES REACTIVE EXTENSIONS PLUS STABLES par jay
Lorsque l'on développe des applications .NET, les exceptions non gérées dans des threads ont le désagréable effet de terminer le processus courant.
Dans l'exemple suivant.......(read more) ...
Cliquez pour lire la suite de l'article par jay
Forum
DE L'AIIIDE!!DE L'AIIIDE!! par eliramomo
Cliquez pour lire la suite par eliramomo
Logiciels
Microsoft Office (2010)MICROSOFT OFFICE (2010)Microsoft Office 2010 offre de nouveaux moyens flexibles et puissants pour optimiser votre travai... Cliquez pour télécharger Microsoft Office SeaMonkey (2.0.7)SEAMONKEY (2.0.7)Le projet SeaMonkey est issu d'un effort communautaire pour developper une application tout en un... Cliquez pour télécharger SeaMonkey Safari (5.0.2)SAFARI (5.0.2)Le navigateur d'Apple a lui aussi été mis à jour, aussi bien dans sa mouture Windows que celle po... Cliquez pour télécharger Safari Mozilla FireFox (4.0 béta 5)MOZILLA FIREFOX (4.0 BéTA 5)Firefox 4.0 béta 5
L'une des nouveautés visibles les plus attendues réside sans doute dans l'a... Cliquez pour télécharger Mozilla FireFox Mozilla Firefox (3.6.9)MOZILLA FIREFOX (3.6.9)Firefox 3.6.9 corrige les problèmes suivants :
* Introduced support for the X-FRAME-OPTION... Cliquez pour télécharger Mozilla Firefox
|