déc 07 2007

Simulation d’un système de drainage dans une mine

Published by Romain Bouleis under Developpement, Réseaux

Simulation d’un système de drainage dans une mine en C++ et MPI avec une interface en Java

On s’intéresse ici à la réalisation d’un système de commande assurant une fonction de drainage dans une mine. Le but de ce système est de réguler le niveau d’eau au fond de la mine, par la mise en route d’une pompe lorsqu’un certain seuil (« niveau-eau-haut ») est atteint voir dépassé et ceci jusqu’à ce qu’il soit ramené au niveau d’un autre seuil (« niveau-eau-bas »).
La pompe ne doit toutefois pas fonctionner si les niveau en gaz toxiques présents dans la galerie, méthane et monoxyde de carbone, sont supérieurs à certains seuils (« seuil-CH4 » et « seuil CO »). Un ventilateur permet donc, lorsque cela est nécessaire, d’évacuer ces gaz vers la surface. On souhaite par ailleurs minimiser l’utilisation du ventilateur.

Drainage

Seront utilisés pour modéliser ce système :

  • MPI pour la communication en entre les différents processus (pompe, capteurs, ventilateur…)
  • C++ comme langage de développement pour l’applicatif
  • Le langage Java avec Swing pour l’interface graphique
  • Les threads et les sockets en C++ et en Java pour la communication entre l’applicatif et l’interface

Le rapport avec les sources en annexe.

No responses yet

déc 02 2007

Communication entre Java et C++ grâce aux sockets

Published by Romain Bouleis under Developpement, Réseaux

Lors de la réalisation d’une application, j’ai été confronté au problème suivant : faire communiquer Java et C++. Il existe plusieurs moyen pour parvenir à cela :

  • L’utilisation des pipes
  • L’utilisation d’un fichier commun
  • L’utilisation des stdin et stdout
  • L’utilisation d’une solution réseau : corba, socket…

C’est cette dernière solution que j’ai choisi et dont ce billet va traiter.

Lors de ce type de communication, il faut nécessairement un serveur et un client. Le serveur devra être exécuté avant le client qui s’y connectera. Une fois la connexion établie, il n’y a plus de différences entre le client et le serveur, les deux attendront un éventuel message, et les deux seront prêt à en émettre.

Pour pouvoir se faire (être prêt à émettre et à recevoir en même temps), le client et le serveur devront être multithread, un thread sera chargé d’attendre un message et un autre d’en envoyer.

Dans cet exemple, l’application Java aura le rôle de serveur, et application C++ aura le rôle de client. Si vous comprenez bien le mécanisme, vous n’aurez pas de mal à les intervertir.

Tout d’abord, intéressons nous au serveur (Serveur.java)

Pour faire un Thread en Java, une méthode consiste à faire une classe qui étend de « Thread»  et qui redéfinit la méthode « run» . Le contenu de cette méthode sera celui exécuté par le thread. Dans notre cas, cette méthode devra attendre qu’un client se connecte puis attendra un éventuel message :


/**
 *
 * @author Romain Bouleis www.bouleis.fr
 *
 */
public class Server extends Thread{
	private int port;
	private boolean run = true;
	private PrintWriter out;
	private BufferedReader in;
	public Server(int port) {
		this.port = port;
	}
	/**
	 * {@docRoot} start the server
	 */
	public void run() {
		ServerSocket server;
		Socket client;
		try {
			//crée un nouveau socket
			server = new java.net.ServerSocket (this.port);
			//attend un client
			client  = server.accept();
			System.out.println("[Server] client connected");
			//writer sur le socket
			out = new PrintWriter(client.getOutputStream(), true);
			//reader sur le soket
			in  = new BufferedReader (new InputStreamReader(client.getInputStream()));
			String msg = "";
			//tant que le serveur est actif et que le client est connecte
			while(this.run && msg != null) {
				//attend un message
				msg = in.readLine();
				//traiter le message
				System.out.println("[server] message reçu : "+msg);
				//arete le serveur si le message est "exit"
				if("exit".equals(msg)) this.run = false;
			}
			//ferme le reader et le writer
			out.close();
			in.close();
			//ferme le socket
			client.close();
			server.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String args[]) {
		Server s = new Server(8000);
		s.start();
	}
}

Ce code executera un serveur attendant un client sur le port 8000. Pour pouvoir envoyer un message à un éventuel client, il faut rajouter une méthode :


public void sendCommand(String c) {
	if(out != null) out.println(c);
	else System.err.println("no client");
}

public static void main(String args[]) {
	Server s = new Server(8000);
	s.start();
	//attendre la connexion d'un client
	s.sendCommand("envoie de cette ligne au client");
}

On peut tester le serveur grâce à telnet : telnet localhost 8000. Lors d’envoie de messages, ils devraient s’afficher dans la console depuis laquelle le serveur a été lancé.

Intéressons nous maintenant au client. De la même façon, un thread sera crée pour attendre des messages du serveur.


#define SOCKET_PORT 8000

using namespace std;

int socketDescriptor;

Client::Client() { }

//se connecte au serveur
void Client::init(char* socket_host) {
	struct sockaddr_in serverAddress;
	struct hostent *hostInfo;

	cout << "[Client] connecting..." <<
	//Choix de l'hôte
  	hostInfo = gethostbyname(socket_host);
 	if (hostInfo == NULL) {
    	cout << "[Client] problem interpreting host: " <<
		exit(1);
 	}

	// Creation du socket.
  	socketDescriptor = socket(PF_INET, SOCK_STREAM, 0);
  	if (socketDescriptor < 0) {
   		cerr << "[Client] cannot create socket\n";
    	exit(1);
  	}

	serverAddress.sin_family = hostInfo->h_addrtype;
  	memcpy((char *) &serverAddress.sin_addr.s_addr,
    hostInfo->h_addr_list[0], hostInfo->h_length);
  	serverAddress.sin_port = htons(SOCKET_PORT);
 	memset(serverAddress.sin_zero, '\0', sizeof serverAddress.sin_zero);

	connect(socketDescriptor, (struct sockaddr *)&serverAddress, sizeof(serverAddress));

	cout << "[Client] connected to server" <<
}

//cree un thread executant la methode runWaitMessage
pthread_t Client::runWaitMessageThread() {
	pthread_t attente;
	(void) pthread_create(&attente, NULL, Client::runWaitMessage, (void*) &socketDescriptor);
	return attente;
}

//attends des messages
void * Client::runWaitMessage(void * args) {
	cout << "[Client] Waiting messages thread running..." <
	char line[255];
	memset(line, '\0', sizeof(line));
	while(recv(socketDescriptor, line, sizeof(line), 0) > 1) {
		//remove the \n at the end of the string
		unsigned int i=0;
		char line_[strlen(line)-1];
		for(i=0;i<strlen(line);i++)
			line_[i] = line[i];
		}
		line_[i] = '\0';
		cout << "[Client] " << line_ << " received" <<

		//on traite le message

		memset(line, '\0', sizeof(line));
	}
	return (void *) 1;
}

//send a command
void Client::sendCommande(string s) {
	char * message;
	string s_ = s;
	s += "\r\n";
	message = (char *) s.c_str();
	send(socketDescriptor,message,strlen(message),0);
	cout << "[Client] " << s_ << " sent" <
}

//close the socket
void Client::closeClient() {
	close(socketDescriptor);
	cout << "[Client] disconnected" <<
}

Enfin, on peut lancer le client avec la méthode suivante :


int main(int argc, char* argv[]) {
	Client *client = new Client();
	client->init("localhost");
	client->runWaitMessageThread();
	client->sendCommande(message);
}

No responses yet

nov 05 2007

MPI 2 : Des concepts à la réalisation

Published by Romain Bouleis under Developpement

Tutoriel et exemples sur la programmation parallèle grâce à MPI.

De nos jours, les avancées technologiques orientent les concepteurs de systèmes vers une augmentation du nombre de ressources pour effectuer un traitement plutôt qu’augmenter la puissance d’une ressource pour exécuter ce même traitement. Ceci est la conséquence de phénomènes physiques empêchant une augmentation infinie de la puissance des ressources. Nous en voulons pour preuve l’annonce par Gordon Moore en septembre 2007 prédisant la désuétude de sa loi selon laquelle le nombre de transistors sur une puce de silicium double tous les deux ans. De ce fait, afin d’accroître la puissance de calcul, la mise en parallèle de plusieurs ressources est l’alternative la plus crédible.

L’ouvrage en pdf, les sources

Table des matières

Du parallélisme à MPI

1. Pourquoi programmer des applications parallèles ?

2. Problèmes liés à la programmation parallèles ?

3. Quels sont les architectures existantes ?

4. Comment MPI-2 répond à nos attentes ?

Installation de l’environnement et premier programme

1. Les composants nécessaires au développement

a. OpenMPI
b. Eclipse et PTP

2. Installation des composants

a. Eclipse
b. CDT
c. OpenMPI
d. PTP
e. PLDT

3. Configuration préliminaire

a. Lancement d’Eclipse
b. Configuration

4. Hello World

Les concepts par l’exemple

1. Squelette d’un programme MPI

2. L’envoi et la réception de message

a. Les fonctions Send et Recv
b. Les types de données OpenMPI
c. L’envoi de messages point à point en mode synchrone
d. Envoie de messages en mode asynchrone

3. Le rendez-vous

4. La diffusion

Cas d’utilisation : le supercalculateur

1. Présentation de l’application

2. Fonctionnement

3. Vu de l’intérieur

4. Conclusion sur le supercalculateur

Conclusion

Table des illustrations

Table des sources

Glossaire

Bibliographie

No responses yet