Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 30/07/2008, à 11:08

rniamo

[Résolu]passer au réseau [C++][SDL_net]

Bonjour,

j'ai presque fini de développer un jeu multijoueur mais pour le moment il ne tourne que session par session ("monojoueur"). Hors le jeu est multijoueur (de 2 à 4).
Aussi j'aimerais ajouter un mode LAN.
Le problème ? Je ne sais pas faire.

Je code en gtkmm/C++ et j'aimerais quelque chose de simple et rapide à mettre en oeuvre (et pourquoi pas portable si possible).

D'avance merci pour vos conseils.

Dernière modification par rniamo (Le 11/08/2008, à 14:32)


< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#2 Le 30/07/2008, à 11:30

tiky

Re : [Résolu]passer au réseau [C++][SDL_net]

La glibmm propose des sockets portables pour le réseau. http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/namespaceGlib.html.
Regarde les IOChannels.
Sinon tu as Gnet: http://www.gnetlibrary.org/ qui utilise la glib mais je pense pas que ça existe pour la glibmm.

Dernière modification par tiky (Le 30/07/2008, à 11:35)


Conseil d'expert: il vous faut un dentifrice adapté...

Hors ligne

#3 Le 30/07/2008, à 13:05

Eldermê

Re : [Résolu]passer au réseau [C++][SDL_net]

Tu as SDL_net (je crois, j'ai jamais essayé) aussi. Ca a l'avantage d'être portable.


Mon blog : petit projet de jeux en 3D (libres, bien sûr).

Hors ligne

#4 Le 30/07/2008, à 13:41

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

Si je peux utiliser glibmm c'est pas plus mal (sdl_net me fait ajouter encore des dépendances).

Par contre j'aurais besoin d'un petit tuto parce que je ne sais pas quoi faire avec les iochannels. Et pour le réseau, udp, tcp ?

En gros je voudrait pouvoir jouer via internet et j'ai principalement besoin d'envoyer 3 messages à partir du pc qui à la main à un instant donné.


< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#5 Le 30/07/2008, à 19:58

robrob

Re : [Résolu]passer au réseau [C++][SDL_net]

si tu veux pouvoir jouer sur internet, utilise plutôt du tcp.
l'udp c'est bien en réseau local.

Hors ligne

#6 Le 30/07/2008, à 20:37

Link31

Re : [Résolu]passer au réseau [C++][SDL_net]

Et boost.asio.

Pas forcément le plus simple à utiliser, mais le "boost" dans le nom sonne comme un gage d'excellente qualité. Mais de toute façon, si ton jeu n'a pas été prévu dès le début pour le réseau, ça va être dans tous les cas très difficile de l'implémenter.

Et l'udp est très bien pour les FPS et autres jeux rapides, mais évidemment ce n'est pas fiable.

Hors ligne

#7 Le 31/07/2008, à 10:48

yolsgens

Re : [Résolu]passer au réseau [C++][SDL_net]

Je connais pas le C++ encore, mais j'ai fait pas mal de réseaux en C.

Tu peux utiliser les librairies de base du C qui manipulent les sockets http://en.wikipedia.org/wiki/Berkeley_sockets et faire communiquer les différences instances du jeu en s'échangeant des messages ASCII.

Par contre c'est vraiment hard à implémenter, j'ai fait 2 projets où j'ai utilisé ça, et c'est VRAIMENT pas simple comme c'est bas niveau. Avec la glib que t'as conseillé tiky tu devrais avoir des fonctions plus simples à mettre en place (des fonctions qui utilisent en faite les fonctions bas niveaux du C...).

Sinon une autre idée comme ça, en python ça prend une poignée de ligne à faire http://docs.python.org/lib/socket-example.html , et il me semble qu'y a une API pour pouvoir mettre du code python dans du C mais j'suis pas certain, faudrait voir dans la doc.

Comme dit Link31, ça va pas être facile à implémenter, bon courage hmm

Dernière modification par yolsgens (Le 31/07/2008, à 10:49)


yolsgens

Hors ligne

#8 Le 31/07/2008, à 16:02

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

En ce qui concerne l'adaptation ça ne devrait pas être trop compliqué (peut-être un peu long mais bon...), je n'ai que 2 fonctions à modifier.

boost::asio à l'air sympa mais je me demande quelle structure mettre en place : il faut que quand un joueur joue, les 3 autres soient au courant. Je voudrais éviter de créer un serveur dédié (je sais que c'est possible mais je ne sais pas comment) pour simplifier l'utilisation, de plus je ne peux à chaque message changer le serveur et les clients.

Au final il me faut une interface du type :

void envoiMessage(std::string& mess);
void callbackReçoitMessage();
// et certainement
void initReseau();
void closeReseau();

< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#9 Le 31/07/2008, à 17:38

nicolas66

Re : [Résolu]passer au réseau [C++][SDL_net]

Juste un truc : nomme tes variables / fonctions en français ou en anglais mais pas en franglais, ca pique les yeux wink


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#10 Le 01/08/2008, à 15:59

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

lol, le franglais me permet de donner rapidement un sens à une fonction ... c'est vrai que ça pique mais ça me parle et comme ce programme ne sera probablement pas repris par quelqu'un d'autre ...

Sinon j'ai regardé http://www.gtkmm.org/docs/gtkmm-2.4/doc … ocket.html
mais ça ne correspond pas à ce que je veux, si ?
Par contre : http://www.gtkmm.org/docs/gtkmm-2.4/doc … ng-io.html a l'air de convenir, je me trompe ?
Cela permet d'après ce que j'ai compris de surveiller le traffic d'un socket. Par contre pour l'ouvrir, le fermer, définir l'IP etc, je chercher encore.

Je jette un coup d'oeil à Gnet.

[HS] vous savez comment les pages de ce types sont faites ? http://www.gnetlibrary.org/docs/, c'est quelquechose du type docygene ? [/HS]

Dernière modification par rniamo (Le 01/08/2008, à 16:01)


< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#11 Le 06/08/2008, à 14:23

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

Bon j'ai fini par partir avec sdl_net, j'essaye de faire une sorte de mini-chat en cli mais j'ai plein de problèmes  (du à sdl_net ou pas) :

voici le code :

// g++ -o test1 testSDL_net.cc -lSDLmain -lSDL_net
/* Utilisation : 
	-> serveur : ./test1 -s pseudo
	-> client : ./test1 pseudo */

#include <SDL/SDL.h>
#include <SDL/SDL_net.h>
#include <iostream>

class ErrConnection
{
	private:
		std::string err;
		
	public:
		ErrConnection(std::string erreur);
		~ErrConnection();
		std::string getErr();
};

ErrConnection::ErrConnection(std::string erreur) : err(erreur)
{
}

ErrConnection::~ErrConnection()
{
}

std::string ErrConnection::getErr()
{
	return err;
}

class SDLNetTCP
{
	private:
		TCPsocket socket;
		TCPsocket connectee; // pour le mode serveur
		IPaddress hote;
		bool serveur;
		std::string nomHote;
		std::string messageRecu;
		
	public:
		static void init();
		static void quit();
		
		SDLNetTCP(std::string domaine, int port); // pour mode connecté, throw ErrConnection
		SDLNetTCP(int port); // pour serveur, throw ErrConnection
		~SDLNetTCP();
		
		void ouvrir(); //  throw ErrConnection
		void envoyer(std::string message);
		std::string recevoir(); // bloquante
		void fermer();
		void fermerConnectee(); // pour le serveur
};

void SDLNetTCP::init()
{
	if (SDL_Init(SDL_INIT_VIDEO)==-1)
		std::cout << "Erreur avec sdl" << std::endl;
	if (SDLNet_Init()==-1)
		std::cout << "Erreur avec sdl_net" << std::endl;
}

void SDLNetTCP::quit()
{
	SDLNet_Quit();
	SDL_Quit();
}

SDLNetTCP::SDLNetTCP(std::string domaine, int port) : socket(NULL), connectee(NULL), serveur(false), messageRecu("")
{
	SDLNet_ResolveHost(&hote,domaine.c_str(),port);
	const char *host=SDLNet_ResolveIP(&hote);
	std::string shost(host);
	nomHote=shost;
	if( !(socket=SDLNet_TCP_Open(&hote)) )
		throw ErrConnection("Impossible de se connecter");
}

SDLNetTCP::SDLNetTCP(int port) : socket(NULL), connectee(NULL), serveur(true), nomHote(""), messageRecu("")
{
	SDLNet_ResolveHost(&hote,NULL,port);
	if( !(socket=SDLNet_TCP_Open(&hote)) )
		throw ErrConnection("Impossible d'écouter le port");
}

void SDLNetTCP::ouvrir()
{
	if (socket)
		return;
	if( !(socket=SDLNet_TCP_Open(&hote)) )
		throw ErrConnection("Impossible d'ouvrir le socket");
}

void SDLNetTCP::envoyer(std::string message)
{
	if (!socket)
		return;
		
	if (!serveur)
		SDLNet_TCP_Send(socket,message.c_str(),message.length()+1);
	else
	{
		while(!connectee)
		{
		    connectee=SDLNet_TCP_Accept(socket);
		}
		SDLNet_TCP_Send(connectee,message.c_str(),message.length()+1);
	}
}

std::string SDLNetTCP::recevoir()
{
	if (socket)
	{
		char buffer[4096];
		buffer[0]='\0';
		if (!serveur)
			SDLNet_TCP_Recv(socket,buffer,4096); // bloquante
		else
		{
			while(!connectee)
			{
			    connectee=SDLNet_TCP_Accept(socket);
			}
			SDLNet_TCP_Recv(connectee,buffer,1024);
		}
		std::string s(buffer);
		messageRecu=s;
	}
	else
		messageRecu="-";
	return messageRecu;
	
	
}

void SDLNetTCP::fermerConnectee()
{
	if (connectee)
	{
		SDLNet_TCP_Close(connectee);
		connectee=NULL;
	}
}

void SDLNetTCP::fermer()
{
	if (socket)
	{
		SDLNet_TCP_Close(socket);
		socket=NULL;
	}
	if (connectee)
	{
		SDLNet_TCP_Close(connectee);
		connectee=NULL;
	}
}

SDLNetTCP::~SDLNetTCP()
{
	fermer();
}


int main(int argc, char** argv)
{
	bool serveur=false;
	
	if (argc>1)
	{
		std::string a1(argv[1]);
		if (a1=="-s")
			serveur=true;
	}
	
	SDLNetTCP::init();

	std::string pseudo="noname";
	if ( argc>2 && serveur)
	{
		std::string str(argv[2]);
		pseudo=str;
	}
	else if (!serveur && argc>1)
	{
		std::string str(argv[1]);
		pseudo=str;
	}
		

	// blabla
	int port=1520; // > 1023
	if (!serveur)
	{
			try
			{
				std::string s;
				SDLNetTCP socket("192.168.0.2",port); 
				do	
				{
					s=socket.recevoir();
					std::cout << s << std::endl;
					std::cout << pseudo << " : ";
					getline(std::cin,s);
					socket.envoyer(pseudo + " : " + s);
				}while(s!="fin");
				socket.fermer();
			}
			catch(ErrConnection& e)
			{
				std::cout << e.getErr() << std::endl;
			}
	}
	else
	{	
			try
			{
				std::string s, stmp;
				SDLNetTCP socket(port);
				do
				{
					std::cout << pseudo << " : ";
					getline(std::cin,stmp);
					if (stmp!="fin")
					{
						socket.envoyer(pseudo + " : " + stmp);
						s=socket.recevoir();
						std::cout << s << std::endl;
					}
				}while(stmp!="fin");
				socket.fermer();
			}
			catch(ErrConnection& e)
			{
				std::cout << e.getErr() << std::endl;
			}
	}

	SDLNetTCP::quit();
	
	return 0;
}

Problèmes :

1) ce code marche en local (serveur et client sur la même machine) mais pas autrement (LAN)
2) comment faire pour pouvoir tchater avec 3 ou 4 machines en même temps
3) comment faire pour que l'ordre de discussion soit quelconque (pour le moment le serveur écrit puis le client puis e serveur etc ...)

Je vois bien la solution d'ouvrir 3 ou 4 threads mais il doit y avoir plus simple, non ?

Dernière modification par rniamo (Le 06/08/2008, à 14:28)


< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#12 Le 07/08/2008, à 15:23

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

Bon j'ai avancé mais il me reste 1 problème :

dans recevoirDeTous() : SDLNet_SocketReady(i->getSocket()) me renvoie toujours faux

// g++ -o SDLNetClasses sdl_net_mult.cc -lSDLmain -lSDL_net
/* pb : 
dans recevoirDeTous() : SDLNet_SocketReady(i->getSocket()) me renvoie toujours faux, 
getline() => retour à ligne obligé ? nettoyer ex : "salut" puis "a" donne "aalut"
commentaires.
merci
*/

#include <cstdlib>
#include <string>
#include <memory>
#include <sstream>
#include <list>
#include <iostream>
#include <SDL/SDL.h>
#include <SDL/SDL_net.h>


// Exception pour gérer les erreurs à la connection
class ErrConnection {
	private:
		std::string err;
		
	public:
		ErrConnection(const std::string& erreur);
		ErrConnection();
		~ErrConnection();
		std::string getErr();
};

ErrConnection::ErrConnection(const std::string& erreur) : err(erreur) {
}

ErrConnection::ErrConnection() : err(SDLNet_GetError()) {
}

ErrConnection::~ErrConnection() {
}

std::string ErrConnection::getErr() {
	return err;
}

// classe virtuelle pour sdl_net en mode tcp
class SDLNet_TCP {
	protected:
		IPaddress adresse;
		TCPsocket sock;
		SDLNet_SocketSet set;
		std::string nomHote;
		int port;

		const static int TAILLE_MAX;		
		static bool initB;
		static bool quitB;
		
	public:
		SDLNet_TCP(); 					// throw ErrConnection	 (inutile ici)
		void ouvrir(); 					// throw ErrConnection

		virtual void envoyer(const std::string& message); 	// throw ErrConnection
		virtual std::string recevoir();
		virtual void fermer();
		
		int getPort();
		const std::string& getNomHote();
		std::string getIP();
		TCPsocket getSocket();
		
		static void init();				// throw ErrConnection
		static void quit();
};

SDLNet_TCP::SDLNet_TCP() : sock(NULL), nomHote("N/A"), port(-1) {
}

const int SDLNet_TCP::TAILLE_MAX=10240; // 10ko
bool SDLNet_TCP::initB=false;
bool SDLNet_TCP::quitB=true;

void SDLNet_TCP::init() {
	if (SDLNet_TCP::initB)
		return;
	if (SDL_Init(0)==-1)
		throw ErrConnection("Erreur d'initialisation de SDL");
	if (SDLNet_Init()==-1)
		throw ErrConnection("Erreur d'initialisation de SDL_net");
	SDLNet_TCP::initB=true;
	SDLNet_TCP::quitB=false;
};

void SDLNet_TCP::quit() {
	if (SDLNet_TCP::quitB)
		return;
	SDLNet_Quit();
	SDL_Quit();
	SDLNet_TCP::initB=false;
	SDLNet_TCP::quitB=true;
};

TCPsocket SDLNet_TCP::getSocket() {
	return sock;
}

void SDLNet_TCP::envoyer(const std::string& message) {
	if (!sock)
		throw ErrConnection("Socket pas pret a envoyer");
	if (SDLNet_TCP_Send(sock,message.c_str(),message.length())<(int)message.length())
		throw ErrConnection("Erreur : SDLNet_TCP_Send() de envoyer()" );
}

std::string SDLNet_TCP::recevoir() {
	if (!sock)
		throw ErrConnection("Socket pas pret a recevoir");
	char message[SDLNet_TCP::TAILLE_MAX];
	message[0]='\0';
	if ( SDLNet_TCP_Recv(sock,message,sizeof(char)*SDLNet_TCP::TAILLE_MAX)!=-1 )
		return std::string(message);
	else
		throw ErrConnection("Erreur lors de la reception");
}

void SDLNet_TCP::ouvrir() {
	if (sock || port<0)
		return;
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection("Erreur : SDL_TCP_Open() de ouvrir()");
}

void SDLNet_TCP::fermer() {
	if (sock)
		SDLNet_TCP_Close(sock);
}

std::string SDLNet_TCP::getIP() {
	std::string err("-1.-1.-1.-1");
	if (port<0)
		return err;
	Uint32 ui=SDL_SwapBE32(adresse.host);
	std::ostringstream os;
	os << (ui >> 24) << "." << ( (ui>>16) & 0xff ) << "." << ( (ui>>8) & 0xff ) << "." << (ui & 0xff);
	return os.str();
}

int SDLNet_TCP::getPort() {
	return port;
}

const std::string& SDLNet_TCP::getNomHote() {
	return nomHote;
}

// Classe pour un client
class Client : public SDLNet_TCP {
	public:
		Client(const std::string& domaine="localhost", int portE=1024);
		Client(TCPsocket sok);
		~Client();
		bool serveurEnvoi();
};

bool Client::serveurEnvoi() {
	if ( SDLNet_CheckSockets(set,0)!=-1 && SDLNet_SocketReady(sock))
			return true;
	return false;
}

Client::Client(const std::string& domaine, int portE) {
	sock=NULL;
	set=NULL;
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection("Erreur du a : SDLNet_AllocSocketSet()");
	if (SDLNet_ResolveHost(&adresse,domaine.c_str(),portE)==-1)
		throw ErrConnection("Erreur du a : SDLNet_ResolveHost()");
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection("Erreur du a : SDLNet_TCP_Open()");
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection("Erreur du a : SDLNet_TCP_AddSocket()");
	const char *nh=SDLNet_ResolveIP(&adresse);
	if (nh)	{
		std::string host(nh);
		nomHote=host;
	}
	port=portE;	
}

Client::Client(TCPsocket sok) {
	sock=NULL;
	set=NULL;
	sock=sok;
	nomHote="N/A";
	port=-1;
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection("Erreur : SDLNet_AllocSocketSet()");
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection("Erreur : SDLNet_TCP_AddSocket()");
}

Client::~Client() {
	if (sock)
		SDLNet_TCP_Close(sock);
	if (set)
		SDLNet_FreeSocketSet(set);
}

class Serveur : public SDLNet_TCP {
	private:
		void ajoutClient(TCPsocket s);	// attention, on ajoute un client de type Client mais tous les champs ne sont pas correctes (ports, IPaddress...)
		void supprimeClient(TCPsocket s);
		void supprimeClient(int n);
		int nbClients;
		std::list<Client> client;
	public:
		const static std::string SORTIR;
		Serveur(int portE=1024);
		~Serveur();
		void creeSocket(); 		// throw ErrConnection
		void envoyerATous(const std::string& message);
		std::string recevoirDeTous();
		void accepterConnexion();
		int getNbConnectee();
};

const std::string Serveur::SORTIR="exit";

int Serveur::getNbConnectee(){
	return client.size();
}

void Serveur::envoyerATous(const std::string& message) {
	try {
		for(std::list<Client>::iterator i=client.begin();i!=client.end();i++)
				i->envoyer(message);
	}
	catch(ErrConnection& e) {
		std::cout << e.getErr() << std::endl;
	}
}

std::string Serveur::recevoirDeTous() {
	int numready;
	if ( (numready=SDLNet_CheckSockets(set,0))!=-1 ) {
		for(std::list<Client>::iterator i=client.begin();i!=client.end();i++) 	{
			try {
				if(SDLNet_SocketReady(i->getSocket()))
				{
					std::string s=i->recevoir();
					if ( s!=Serveur::SORTIR )
						return s;
					else if (s==Serveur::SORTIR)
						supprimeClient(i->getSocket());
				}
			}
			catch(ErrConnection& e) {}
		}
	}
	std::string str("");
	return str;		
}

void Serveur::ajoutClient(TCPsocket s) {
	Client *cl=new Client(s);
	client.push_front(*cl);
	
}

void Serveur::accepterConnexion() {
	TCPsocket cl=NULL;
	if (SDLNet_CheckSockets(set,0)!=-1 && SDLNet_SocketReady(sock) && (cl=SDLNet_TCP_Accept(sock)) )
			ajoutClient(cl);
}

void Serveur::supprimeClient(TCPsocket s) {
	std::list<Client>::iterator i=client.begin();
	while(i!=client.end() && i->getSocket()!=s)
		i++;
	if (i==client.end())
		return;
	i->fermer();
	client.erase(i);
	nbClients--;
}

void Serveur::supprimeClient(int n) {
	if (n<0 || n>=nbClients)
		return;
	std::list<Client>::iterator i=client.begin();
	int nb=0;
	while(i!=client.end() && nb<n)
		i++;
	i->fermer();
	client.erase(i);
	nbClients--;
}

void Serveur::creeSocket() {
	if(set)
		SDLNet_FreeSocketSet(set);
	if ( !(set=SDLNet_AllocSocketSet(nbClients+1)) )
		throw ErrConnection();
	SDLNet_TCP_AddSocket(set,sock);
	for(std::list<Client>::iterator i=client.begin();i!=client.end();i++)
		SDLNet_TCP_AddSocket(set,i->getSocket());	
}

Serveur::Serveur(int portE) : nbClients(0) {
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection();
	if (SDLNet_ResolveHost(&adresse,NULL,portE)==-1)
		throw ErrConnection();
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection();
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection();
	const char *nh=SDLNet_ResolveIP(&adresse);
	if (nh) {
		std::string host(nh);
		nomHote=host;
	}
	port=portE;	
}

Serveur::~Serveur() {
	client.clear();
};

int main(int argc, char **argv)
{
	if (argc<3) {
		std::cout << "\tUsage :\n\t\tServeur : SDLNetClasses -s pseudo\n\t\tClient : SDLNetClasses -c pseudo" << std::endl;
		exit(0);
	}
	
	bool serveur=false;
	std::string serv(argv[1]);
	if (serv=="-s")
		serveur=true;
	std::string pseudo(argv[2]);
	
	try {
		SDLNet_TCP::init();
	}
	catch(ErrConnection& e) {
		std::cout << e.getErr() << std::endl;
	}
	
	int port=1025;
	if (serveur) {
		try {
			Serveur serveur(port);
			std::cout << "Serveur prêt." << std::endl;
			std::cout << "Vous êtes sur la machine : " << serveur.getNomHote() << std::endl;
			std::cout << "Vous avez l'IP : " << serveur.getIP() << std::endl;
			std::cout << "--------------------------" << std::endl;
			std::cout << std::endl;
			
			while(true) {
				serveur.creeSocket();
				serveur.accepterConnexion();
				if (serveur.getNbConnectee()) {
					std::string s;
					s.erase();
					s=serveur.recevoirDeTous();
					if (s.length()) {
						serveur.envoyerATous(s);
						std::cout << s << std::endl;
					}
				}
			}
		}
		catch(ErrConnection& e) {
			std::cout << "Erreur serveur : '" << e.getErr() << "'" << std::endl;
		}		
	}
	else {
		try {
			Client client("localhost",port);
			std::cout << "Vous êtes sur la machine : " << client.getNomHote() << std::endl;
			std::cout << "Vous avez l'IP : " << client.getIP() << std::endl;
			std::cout << "Vous êtes prêt, tapez un message." << std::endl;
			std::cout << "---------------------------------" << std::endl;
			std::cout << std::endl;

			bool bcl=true;
			while(bcl) {
				if (!client.serveurEnvoi())
				{
					std::string message;
					getline(std::cin,message);
					if (message=="exit") {
						message="* " + pseudo + " quit.";
						bcl=false;
					}
					else				
						message=pseudo + " : " + message;
					client.envoyer(message);
				}
				
				std::string s=client.recevoir();
				std::cout << "'"+s+"'" << std::endl;
			}
		}
		catch(ErrConnection& e) {
			std::cout << "Erreur client : '" << e.getErr() << "'" << std::endl;
		}
	}
	
	SDLNet_TCP::quit();
	
	return 0;
}

Dernière modification par rniamo (Le 07/08/2008, à 15:55)


< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne

#13 Le 07/08/2008, à 17:51

rniamo

Re : [Résolu]passer au réseau [C++][SDL_net]

Je poste la dernière version du code où il n'y a plus que ce petit problème a priori (pour le moment) :

// g++ -o SDLNetClasses sdl_net_mult.cc -lSDLmain -lSDL_net
/* pb : 
dans recevoirDeTous() : SDLNet_SocketReady(i->getSocket()) me renvoie toujours faux, 
getline() => retour à ligne obligé ? nettoyer ex : "salut" puis "a" donne "aalut"
commentaires.
merci
*/

#include <cstdlib>
#include <string>
#include <memory>
#include <sstream>
#include <list>
#include <limits> 
#include <iostream> 
#include <SDL/SDL.h>
#include <SDL/SDL_net.h>


// Exception pour gérer les erreurs à la connection
class ErrConnection {
	private:
		std::string err;
		
	public:
		ErrConnection(const std::string& erreur);
		ErrConnection();
		~ErrConnection();
		std::string getErr();
};

ErrConnection::ErrConnection(const std::string& erreur) : err(erreur) {
}

ErrConnection::ErrConnection() : err(SDLNet_GetError()) {
}

ErrConnection::~ErrConnection() {
}

std::string ErrConnection::getErr() {
	return err;
}

// classe virtuelle pour sdl_net en mode tcp
class SDLNet_TCP {
	protected:
		IPaddress adresse;
		TCPsocket sock;
		SDLNet_SocketSet set;
		std::string nomHote;
		int port;

		const static int TAILLE_MAX;		
		static bool initB;
		static bool quitB;
		
	public:
		SDLNet_TCP(); 					// throw ErrConnection	 (inutile ici)
		void ouvrir(); 					// throw ErrConnection

		virtual void envoyer(const std::string& message); 	// throw ErrConnection
		virtual std::string recevoir();
		virtual void fermer();
		
		int getPort();
		const std::string& getNomHote();
		std::string getIP();
		TCPsocket getSocket();
		
		static void init();				// throw ErrConnection
		static void quit();
};

SDLNet_TCP::SDLNet_TCP() : sock(NULL), nomHote("N/A"), port(-1) {
}

const int SDLNet_TCP::TAILLE_MAX=10240; // 10ko
bool SDLNet_TCP::initB=false;
bool SDLNet_TCP::quitB=true;

void SDLNet_TCP::init() {
	if (SDLNet_TCP::initB)
		return;
	if (SDL_Init(0)==-1)
		throw ErrConnection("Erreur d'initialisation de SDL");
	if (SDLNet_Init()==-1)
		throw ErrConnection("Erreur d'initialisation de SDL_net");
	SDLNet_TCP::initB=true;
	SDLNet_TCP::quitB=false;
};

void SDLNet_TCP::quit() {
	if (SDLNet_TCP::quitB)
		return;
	SDLNet_Quit();
	SDL_Quit();
	SDLNet_TCP::initB=false;
	SDLNet_TCP::quitB=true;
};

TCPsocket SDLNet_TCP::getSocket() {
	return sock;
}

void SDLNet_TCP::envoyer(const std::string& message) {
	if (!sock)
		throw ErrConnection("Socket pas pret a envoyer");
	if (SDLNet_TCP_Send(sock,message.c_str(),message.length())<(int)message.length())
		throw ErrConnection("Erreur : SDLNet_TCP_Send() de envoyer()" );
}

std::string SDLNet_TCP::recevoir() {
	if (!sock)
		throw ErrConnection("Socket pas pret a recevoir");
	char message[SDLNet_TCP::TAILLE_MAX]={'\0'};
	if ( SDLNet_TCP_Recv(sock,message,sizeof(char)*SDLNet_TCP::TAILLE_MAX)!=-1 )
		return std::string(message);
	else
		throw ErrConnection("Erreur lors de la reception");
}

void SDLNet_TCP::ouvrir() {
	if (sock || port<0)
		return;
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection("Erreur : SDL_TCP_Open() de ouvrir()");
}

void SDLNet_TCP::fermer() {
	if (sock)
		SDLNet_TCP_Close(sock);
}

std::string SDLNet_TCP::getIP() {
	std::string err("-1.-1.-1.-1");
	if (port<0)
		return err;
	Uint32 ui=SDL_SwapBE32(adresse.host);
	std::ostringstream os;
	os << (ui >> 24) << "." << ( (ui>>16) & 0xff ) << "." << ( (ui>>8) & 0xff ) << "." << (ui & 0xff);
	return os.str();
}

int SDLNet_TCP::getPort() {
	return port;
}

const std::string& SDLNet_TCP::getNomHote() {
	return nomHote;
}

// Classe pour un client
class Client : public SDLNet_TCP {
	public:
		Client(const std::string& domaine="localhost", int portE=1024);
		Client(TCPsocket sok);
		~Client();
		bool serveurEnvoi();
};

bool Client::serveurEnvoi() {
	if ( SDLNet_CheckSockets(set,0)!=-1 && SDLNet_SocketReady(sock))
			return true;
	return false;
}

Client::Client(const std::string& domaine, int portE) {
	sock=NULL;
	set=NULL;
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection("Erreur du a : SDLNet_AllocSocketSet()");
	if (SDLNet_ResolveHost(&adresse,domaine.c_str(),portE)==-1)
		throw ErrConnection("Erreur du a : SDLNet_ResolveHost()");
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection("Erreur du a : SDLNet_TCP_Open()");
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection("Erreur du a : SDLNet_TCP_AddSocket()");
	const char *nh=SDLNet_ResolveIP(&adresse);
	if (nh)	{
		std::string host(nh);
		nomHote=host;
	}
	port=portE;	
}

Client::Client(TCPsocket sok) {
	sock=NULL;
	set=NULL;
	sock=sok;
	nomHote="N/A";
	port=-1;
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection("Erreur : SDLNet_AllocSocketSet()");
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection("Erreur : SDLNet_TCP_AddSocket()");
}

Client::~Client() {
	if (sock)
		SDLNet_TCP_Close(sock);
	if (set)
		SDLNet_FreeSocketSet(set);
}

class Serveur : public SDLNet_TCP {
	private:
		void ajoutClient(TCPsocket s);	// attention, on ajoute un client de type Client mais tous les champs ne sont pas correctes (ports, IPaddress...)
		void supprimeClient(TCPsocket s);
		void supprimeClient(int n);
		int nbClients;
		std::list<Client> client;
	public:
		const static std::string SORTIR;
		Serveur(int portE=1024);
		~Serveur();
		void creeSocket(); 		// throw ErrConnection
		void envoyerATous(const std::string& message);
		std::string recevoirDeTous();
		void accepterConnexion();
		int getNbConnectee();
};

const std::string Serveur::SORTIR="exit";

int Serveur::getNbConnectee(){
	return client.size();
}

void Serveur::envoyerATous(const std::string& message) {
	try {
		for(std::list<Client>::iterator i=client.begin();i!=client.end();i++)
				i->envoyer(message);
	}
	catch(ErrConnection& e) {
		std::cout << e.getErr() << std::endl;
	}
}

std::string Serveur::recevoirDeTous() {
	int numready;
	if ( client.size() && (numready=SDLNet_CheckSockets(set,0))!=-1 ) {
		for(std::list<Client>::iterator i=client.begin();i!=client.end();i++) 	{
			try {
				//if(SDLNet_SocketReady(i->getSocket()))
				{
					std::string s("");
					s=i->recevoir();
					if ( s!=Serveur::SORTIR )
						return s;
					else
						supprimeClient(i->getSocket());
				}
			}
			catch(ErrConnection& e) {}
		}
	}
	std::string str("");
	return str;		
}

void Serveur::ajoutClient(TCPsocket s) {
	Client *cl=new Client(s);
	client.push_front(*cl);
	
}

void Serveur::accepterConnexion() {
	TCPsocket cl=NULL;
	if (SDLNet_CheckSockets(set,0)!=-1 && SDLNet_SocketReady(sock) && (cl=SDLNet_TCP_Accept(sock)) )
			ajoutClient(cl);
}

void Serveur::supprimeClient(TCPsocket s) {
	std::list<Client>::iterator i=client.begin();
	while(i!=client.end() && i->getSocket()!=s)
		i++;
	if (i==client.end())
		return;
	i->fermer();
	client.erase(i);
	nbClients--;
}

void Serveur::supprimeClient(int n) {
	if (n<0 || n>=nbClients)
		return;
	std::list<Client>::iterator i=client.begin();
	int nb=0;
	while(i!=client.end() && nb<n)
		i++;
	i->fermer();
	client.erase(i);
	nbClients--;
}

void Serveur::creeSocket() {
	if(set)
		SDLNet_FreeSocketSet(set);
	if ( !(set=SDLNet_AllocSocketSet(nbClients+1)) )
		throw ErrConnection();
	SDLNet_TCP_AddSocket(set,sock);
	for(std::list<Client>::iterator i=client.begin();i!=client.end();i++)
		SDLNet_TCP_AddSocket(set,i->getSocket());	
}

Serveur::Serveur(int portE) : nbClients(0) {
	if ( !(set=SDLNet_AllocSocketSet(1)) )
		throw ErrConnection();
	if (SDLNet_ResolveHost(&adresse,NULL,portE)==-1)
		throw ErrConnection();
	if(SDLNet_TCP_AddSocket(set,sock)==-1)
		throw ErrConnection();
	if ( !(sock=SDLNet_TCP_Open(&adresse)) )
		throw ErrConnection();
	const char *nh=SDLNet_ResolveIP(&adresse);
	if (nh) {
		std::string host(nh);
		nomHote=host;
	}
	port=portE;	
}

Serveur::~Serveur() {
	client.clear();
};

int main(int argc, char **argv)
{
	if (argc<3) {
		std::cout << "\tUsage :\n\t\tServeur : SDLNetClasses -s pseudo\n\t\tClient : SDLNetClasses -c pseudo" << std::endl;
		exit(0);
	}
	
	bool serveur=false;
	std::string serv(argv[1]);
	if (serv=="-s")
		serveur=true;
	std::string pseudo(argv[2]);
	
	try {
		SDLNet_TCP::init();
	}
	catch(ErrConnection& e) {
		std::cout << e.getErr() << std::endl;
	}
	
	int port=1025;
	if (serveur) {
		try {
			Serveur serveur(port);
			std::cout << "Serveur prêt." << std::endl;
			std::cout << "Vous êtes sur la machine : " << serveur.getNomHote() << std::endl;
			std::cout << "Vous avez l'IP : " << serveur.getIP() << std::endl;
			std::cout << "--------------------------" << std::endl;
			std::cout << std::endl;
			
			while(true) {
				serveur.creeSocket();
				serveur.accepterConnexion();
				if (serveur.getNbConnectee()) {
					std::string s;
					s.erase();
					s=serveur.recevoirDeTous();
					if (s.length()) {
						serveur.envoyerATous(s);
						std::cout << s << std::endl;
					}
				}
			}
		}
		catch(ErrConnection& e) {
			std::cout << "Erreur serveur : '" << e.getErr() << "'" << std::endl;
		}		
	}
	else {
		try {
			Client client("localhost",port);
			std::cout << "Vous êtes sur la machine : " << client.getNomHote() << std::endl;
			std::cout << "Vous avez l'IP : " << client.getIP() << std::endl;
			std::cout << "Vous êtes prêt." << std::endl;
			std::cout << "---------------------------------" << std::endl;
			std::cout << std::endl;

			bool bcl=true;
			while(bcl) {
				if (!client.serveurEnvoi())
				{
					std::string message;
					std::cout << "tapez un message : " ;
					getline(std::cin,message);
					if (message.length()>0)
						message[message.length()]='\0';
					if (message=="exit") {
						message="* " + pseudo + " quit.";
						bcl=false;
					}
					else				
						message="\t" + pseudo + " : " + message;
					client.envoyer(message);
					//std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
					//std::cin.clear();
				}
				
				std::string s=client.recevoir();
				std::cout << s << std::endl;
			}
		}
		catch(ErrConnection& e) {
			std::cout << "Erreur client : '" << e.getErr() << "'" << std::endl;
		}
	}
	
	SDLNet_TCP::quit();
	
	return 0;
}

< Quelques un des mes programmes  | Cuisine Facile (pour les gourmands) | Fast MVC for PHP >
        \   ^__^
         \  (o o)\_______
            (___)\            )\

Hors ligne