Voici une source permettant de créer des clients et des serveurs basées sur les sockets pour système UNIX.
Pour cela il suffit d'implémenter la méthode virtuelle interaction.
La partie connexion est gérée automatiquement. Chaque connexion d'un client est gérée par un thead.
note : ne fonctionne pas sous windows.
La source contient un exemple d'implémentation d'un client et d'un serveur.
Le serveur cle/valeur implémente les operations suivantes:
- GET CLE
- PUT CLE VALEUR
- DEL CLE
- QUIT
Les applications doivent être lancées à partir du terminal :
serveur : ./server-word-word 23000
client : ./client-word-word localhost 23000
telecharger source :
http://www.megaupload.com/?d=VKWF64L6
Source / Exemple :
#ifndef _SOCKET_HH_
#define _SOCKET_HH_
#include "libsocketException.h"
extern "C"
{
#include <stdlib.h>
#include <stdio.h>
};
#include <iostream>
#include <sstream>
namespace libsocket
{
/*____________________________________________________________________________________________*/
/**
class Socket
{
protected:
int _fd;// descripteur de la socket
virtual void socket() = 0;
virtual void bind(int port) = 0;
public:
Socket();
virtual void close()=0;
void setFd(int fd);
int getFd();
};
}
#endif
#include "libsocketTcp.h"
extern "C"
{
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
};
#include <iostream>
#include <sstream>
#include <pthread.h> // librairie thread
namespace libsocket
{
/*************************************************************************/
/** Server **/
/*************************************************************************/
/*_____________________________________________________________________________*/
/**
void ServerTcp::run(int port)
{
socket();
bind(port);
listen(10);
loop();
}
/*_____________________________________________________________________________*/
/**
void ServerTcp::loop()
{
/*while (true)
{
SocketTcp client;
accept(client);
std::cout<<"apres:"<<client.getFd()<<std::endl;
if(fork() == 0)
{
printf("connexion \n");
interaction(client);
client.close();
printf("deconnexion \n");
exit(0);
}
}*/
while (true)
{
SocketTcp* client = new SocketTcp();
accept(*client);
pthread_t num_thread[1];
void * tab[2] = {this,client};
if (pthread_create(&num_thread[0], NULL, (void *(*)(void *))&ServerTcp::startThread,tab) == -1)
perror ("problème creation du thread\n");
}
}
/*_____________________________________________________________________________*/
/**
- on est obligé de passer par une métode static pour utiliser un thread
void* ServerTcp::startThread ( void* Parameters[] )
{
ServerTcp* server = reinterpret_cast<ServerTcp*>(Parameters[0]);//recupere l'objet Server
SocketTcp* client = reinterpret_cast<SocketTcp*>(Parameters[1]);//recupere la socket client
server->runThread(client);
}
/*_____________________________________________________________________________*/
/**
- methode appelé par le thread
void ServerTcp::runThread(SocketTcp* client)
{
printf("connexion\n");
interaction(*client);//appel de la methode virtuelle interaction
client->close();//fermeture de la socket
delete client;//liberation du pointeur client déclaré dans Server::loop
printf("deconnexion \n");
pthread_exit(NULL);//detruit le thread
}
/*************************************************************************/
/** Client **/
/*************************************************************************/
/*_____________________________________________________________________________*/
/**
- utilise les méthodes de Socket pour établir une connexion
- à une serveur lancer l'interaction
void ClientTcp::run(const char* host, int port)
{
socket();
connect(host,port);
interaction();
close();
}
/*_____________________________________________________________________________*/
/**
- cette variante appelle la précédente
void ClientTcp::run(string& host, int port)
{
run(host.c_str(),port);
}
};
#include "socketTcp.h"
#include <iostream>
using namespace std;
namespace libsocket
{
/*_____________________________________________________________________________*/
/**
- invoque l'appel système socket
void SocketTcp::socket()
{
_fd = ::socket(PF_INET, SOCK_STREAM, 0); // appel la fonction socket de c.
if (_fd < 0) throw ErrnoExcept("socket");
}
/*_____________________________________________________________________________*/
void SocketTcp::connect(const char* host, int port)
{
ostringstream os;
os<<port;
socket();
struct addrinfo *serv_addr = 0;
int k = getaddrinfo(host,os.str().c_str(),0,&serv_addr);//obtebir une structure d adresse
if(k != 0)
throw ErrnoExcept("getaddrinfo");
while(k=::connect(_fd,serv_addr->ai_addr,serv_addr->ai_addrlen))
{
if(k<0)
if (errno==EAGAIN || errno==EINTR) continue;
else
throw ErrnoExcept("serveur indisponible");
}
freeaddrinfo(serv_addr);
}
/*_____________________________________________________________________________*/
/**
void SocketTcp::close()
{
while (_fd >= 0)
{
int r = ::close(_fd);
if (r < 0)
{
if (errno == EINTR) continue;
else throw ErrnoExcept("close");
}
break;
}
_fd = -1;
}
/*_____________________________________________________________________________*/
/**
- lie la socket au port sur toutes les interfaces.
void SocketTcp::bind(int port)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (::bind(_fd, (struct sockaddr *) &addr, sizeof(addr))==-1)
throw ErrnoExcept("bind");
}
/*_____________________________________________________________________________*/
/**
- \c listen pour indiquer qu'on va écouter sur cette socket.
void SocketTcp::listen(int backlog)
{
if (::listen(_fd, backlog)==-1)
throw ErrnoExcept("listen");
}
/*_____________________________________________________________________________*/
/**
- Pour attendre et accepter une demande de connexion d'un client. C
void SocketTcp::accept(Socket& client)
{
while (true)
{
int cli = ::accept(_fd, NULL, NULL);
if (cli < 0)
{
//cas exceptionnels de fonctionnement normal
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue;
else throw ErrnoExcept("accept");
}
client.setFd(cli);
break;
}
}
/*_____________________________________________________________________________*/
/**
- écrit sur la socket exactement n octets pointés par buf.
void SocketTcp::write(const char* buf, int n)
{
while (n > 0)
{
int k = ::write(_fd, buf, n);
if (k < 0)
{
if (errno == EAGAIN || errno == EINTR) continue;
else throw ErrnoExcept("write");
}
buf += k;
n -= k;
}
}
/*_____________________________________________________________________________*/
/**
- ecrit sur la socket en calculant elle-même la
- longueur de la chaîne de caractères.
void SocketTcp::write(const char* buf)
{
write(buf, strlen(buf)+1);//+1 pour compter le '\0'
}
/*_____________________________________________________________________________*/
/**
/**
- Pour attendre et accepter une demande de connexion d'un client.
void SocketTcp::write(const string& buf)
{
write(buf.c_str(), buf.length()+1);//+1 pour compter le '\0'
}
/*_____________________________________________________________________________*/
void SocketTcp::read(char *buf,int n)
{
while (n > 0)
{
int k = ::read(_fd, buf, n);
if (k < 0)
if (errno == EAGAIN || errno == EINTR) continue;
else throw ErrnoExcept("read");
buf += k;
n -= k;
}
}
/*_____________________________________________________________________________*/
/**
- lit sur la socket exactement n octets et les retourne sous
la forme d'un string. (ne pas compter le caractère de fin de chaine '\0')
string SocketTcp::read(int n)
{
char mes[n+1]; //a corriger !!
read(mes,n);
int taille = strlen(mes);
if(mes[taille] != '\0')
mes[taille+1] = '\0';
return (string) mes;
}
/*_____________________________________________________________________________*/
/**
int32_t SocketTcp::readInt32()
{
int32_t v;
read((char *) &v,sizeof(v));
return ntohl(v);
}
/*_____________________________________________________________________________*/
/**
void SocketTcp::writeInt32(int i)
{
int32_t v = htonl(i);
write (( const char *) &v,sizeof(v));
}
/*_____________________________________________________________________________*/
/**
- lit une ligne de texte et retourne un string (sans le \n)
string SocketTcp::readLine()
{
char c;
ostringstream os;
while(true)
{
int k = ::read(_fd,&c,1);
if (k <= 0)//si k==0 on leve une exception pour eviter une boucle infinie
if (errno == EAGAIN || errno == EINTR) continue;
else throw ErrnoExcept("readline");
if(c == EOF || c == '\0' || c == '\n') break;
else os << c;
}
return os.str();
}
/*_____________________________________________________________________________*/
/**
- lit un mot délimité par un espaces.
string SocketTcp::readWord()
{
char c;
ostringstream res ;
int k;
//supprime les espaces
while(true)
{
k = ::read(_fd,&c,1);
if (k <= 0) //si k==0 on leve une exception pour eviter une boucle infinie
if (errno == EAGAIN || errno == EINTR) continue;
else throw ErrnoExcept("readword");
if(c == EOF || c == '\n' || c == '\0') return "";
if(!isspace(c))
{
res<<c;
break;
}
}
//lecture d'un mot
while(true)
{
k= ::read(_fd,&c,1);
if (k <= 0)
if (errno == EAGAIN || errno == EINTR) continue;
else throw ErrnoExcept("readword");
if(c == EOF || c == '\0' || c == '\n' || isspace(c)) break;
else
res << c;
}
return res.str();
}
}
#include "socketUdp.h"
#include <iostream>
using namespace std;
namespace libsocket
{
/*_____________________________________________________________________________*/
/**
- invoque l'appel système socket
void SocketUdp::socket()
{
_fd = ::socket(AF_INET, SOCK_DGRAM, 0); // appel la fonction socket de c.
if (_fd < 0) throw ErrnoExcept("socket");
}
/*_____________________________________________________________________________*/
/**
void SocketUdp::close()
{
while (_fd >= 0)
{
int r = ::close(_fd);
if (r < 0)
{
if (errno == EINTR) continue;
else throw ErrnoExcept("close");
}
break;
}
_fd = -1;
}
/*_____________________________________________________________________________*/
/**
- lie la socket au port sur toutes les interfaces.
void SocketUdp::bind(int port)
{
this->addr.sin_family = AF_INET;
this->addr.sin_port = htons(port);
this->addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (::bind(this->_fd, (struct sockaddr *) &this->addr, sizeof(this->addr))!=0)
throw ErrnoExcept("bind");
}
/*_____________________________________________________________________________*/
/**
void SocketUdp::sendto(const char* mes)
{
::sendto(this->getFd(),mes,strlen(mes)+1,0,(struct sockaddr*)&this->addr,sizeof(addr));
}
/*_____________________________________________________________________________*/
/**
void SocketUdp::sendto(string mes)
{
sendto(mes.c_str());
}
/*_____________________________________________________________________________*/
/**
string SocketUdp::recvfrom(int n)
{
char mes[n+1];
int flag = ::recvfrom(this->getFd(),mes,n,0,(struct sockaddr*)&this->addr,&this->lg_app);
int taille = strlen(mes);
if(mes[taille] != '\0')
mes[taille+1] = '\0';
return (string) mes;
}
}
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.