[win32] classe de controle de winsock mode multithread

Soyez le premier à donner votre avis sur cette source.

Vue 6 860 fois - Téléchargée 885 fois

Description

Salut !
Bon ben voilà...
tout est dans le titre :
il s'agit d'une classe (HelkSock) qui permet de controler facilement des winsocks, et ceci de manière multi-thread...
L'utilisation est simple, le code un peu plus fouillis...

dans le zip, il y a un autre exemple (que ci-dessous) de l'utilisation de la classe HelkSock, qui utilise QT (donc prévoyez les DLL pour faire fonctionner le .exe)

Source / Exemple :


//Principe de fonctionnement
HelkSock HKS(true); //true pour TCP, false pour UDP

//pour se connecter à un hote distant, à l'adresse IP 125.124.123.122 sur le port 1234 :
HKS.Connecter("125.124.123.122", 1234);

//pour se mettre en écoute (listen), cad en attente avec le port 1234 ouvert :
HKS.Ecouter(1234);

//pour se déconnecter :
HKS.Fermer();

//rien de plus simple, donc... mais tout ça c'est bien beau, cependant c'est inutile...
//en effet le but est évidemment d'envoyer et de recevoir des données...
//pour envoyer c'est encore très simple :
char pcBuffer [200] = "Ceci est mon message";
HKS.Envoyer(pcBuffer, strlen(pcBuffer));

//pour l'instant, pas de problème
//mais qu'en est-il de la réception ?

/* C'est là que l'aspect multi-thread de ma classe intervient...
En effet on définit, si possible avant utilisation de l'objet, des fonctions
qui serviront de récepteurs pour les différents messages que le HelkSock va
pouvoir vouloir envoyer... Je me suis pour cela basé sur le principe de fonctionnement des Winsock Control en VB et du système de slots en QT
Voilà comment ça marche : */
HKS.LierSlot1(SLOT_REQUETE, ConnexionEffectuee);
//où ConnexionEffectuee est une fonction de la forme :
//HELKSLOT Slot (); //HELKSLOT = int
//ou encore
HKS.LierSlot2(SLOT_REQUETE, RequeteDeConnexion);
//où on a RequeteDeConnexion de la forme
//HELKSLOT Slot(const char * pcBuffer, const ulong uLongVal);
//et aussi, le dernier type de Slot :
HKS.LierSlot3(SLOT_PROGRESSION, ProgressionEnvoi);
//avec progressionEnvoi qui prend pour arguments (ulong uOctetsEnvoyes, ulong uOctetsRestants)

//ceci dit, on peut simplifier les choses en utilisant LierTousSlots,
//qui ne lie que les slots non NULLs, et qui permet en une ligne d'initialiser correctement la classe

/* Maintenant observons le comportement :
On a "lié" la fonction
HELKSLOT RecevoirDonnees(const char * pcDonneesRecues, const ulong uLongueurDonnees);
à la classe pour indiquer l'événement Réception de données (cad SLOT_RECEPTION)
Une fois que l'on sera connecté, on recevra immédiatement, et sans rien faire, les données dans cette fonction ! voilà tout l'intérêt de la classe...
De meme, 4 (oui c'est peu) messages d'erreur peuvent parvenir à une fonction Erreur, et on peut connaitre l'état d'avancement d'un envoi grace à un slot relié à l'événement SLOT_PROGRESSION.

Voici donc un exemple de code pour clarifier les choses (enfin j'espère) : */

#include <iostream>
#include <string>
#include <stdlib.h>
#include <conio.h>
#include <ctime>
using namespace std;

#include "helksock1.h"

HELKSLOT RequeteDeConnexion(const char * pcAdresseIP, const ulong uPortDistant);
HELKSLOT RecevoirDonnees(const char * pcDonneesRecues, const ulong uLongueurDonnees);
HELKSLOT ConnexionEffectuee();
HELKSLOT FermetureHSocket();
HELKSLOT ErreurHSocket(const char * pcErreurDescr, const ulong uErrNum);
HELKSLOT EnvoiEnCours(ulong uEnvoyes, ulong uRestants);
HELKSLOT FinEnvoi();

	HelkSock hks;

int main()
{
	srand(time(0));
	cout << "Lancement du HelkSock..." << endl;
	hks.LierTousSlots(RequeteDeConnexion,
					ConnexionEffectuee,
					RecevoirDonnees,
					EnvoiEnCours,
					FinEnvoi,
					FermetureHSocket,
					ErreurHSocket
					);
	///*
	//tout d'abord, on essaie de fonctionner en mode serveur, cad qu'on écoute sur le port 42201
	//grace à un autre programme, on peut se connecter sur ce port et envoyer un message, qui sera reçu
	hks.Ecouter(42200);

	cout << "Si vous voulez arreter, enfoncez la touche ENTREE" << endl
		<< "Sinon vous pouvez envoyer des mots ou attendre d'en recevoir" << endl;
	string sEnvoi;
	
	char pcBuffer [500] = {0};
	cout << "Veuillez enfoncer une touche quelconque pour continuer ou ENTREE pour quitter..." << endl;
	while (getch() != '\r')
	{
		cout << "Veuillez entrer une phrase a envoyer" << endl;
		cin >> sEnvoi;
			//on envoie le message tapé
		if (!hks.Envoyer(sEnvoi.c_str(), sEnvoi.length()))
			cout << "ERREUR lors de l'envoi : un autre envoi semble etre en cours" << endl;
		Sleep(100);
		cout << "Veuillez enfoncer une touche quelconque pour continuer ou ENTREE pour quitter..." << endl;
	}
	
	cout << "On attend un peu..." << endl;
	Sleep(2500); //il me faut le temps de mettre l'autre prog en écoute
	//maintenant on veut se connecter à un hote "distant" (127.0.0.1 = localhost)
	hks.Fermer();
	cout << "Tentative de connexion sur soi-meme au port 42201" << endl;
	if (hks.Connecter("127.0.0.1", 42201))
	{
		char pcBuffer [500] = {0};
		cout << "Veuillez enfoncer une touche quelconque pour continuer ou ENTREE pour quitter..." << endl;
		while (getch() != '\r')
		{
			cout << "Veuillez entrer une phrase a envoyer" << endl;
			cin >> sEnvoi;
			//on envoie le message tapé
			if (!hks.Envoyer(sEnvoi.c_str(), sEnvoi.length()))
				cout << "ERREUR lors de l'envoi : un autre envoi semble etre en cours" << endl;
			Sleep(100);
			cout << "Veuillez enfoncer une touche quelconque pour continuer ou ENTREE pour quitter..." << endl;
		}
	}
	//*/

	return 0;
}

//en cas de requete de connexion, l'utilisateur peut être averti
HELKSLOT RequeteDeConnexion(const char * pcAdresseIP, const ulong uPortDistant)
{
	cout << "Requete de connexion de la part de " << pcAdresseIP << " sur le port " << uPortDistant << endl;
	return true; //si on retourne false, alors il y a déconnexion et on attend encore, sinon on accepte et...
}

//...une fois la connexion effectuée, on prévient l'utilsateur
HELKSLOT ConnexionEffectuee()
{
	cout << "La connexion vient de se faire" << endl;
	if (!BLOQUER_ECOUTE)
		hks.LancerReception();
	return true;
}

//ici on recoit en permanence ce que le pc distant veut nous envoyer
HELKSLOT RecevoirDonnees(const char * pcDonneesRecues, const ulong uLongueurDonnees)
{
	cout << "Recu : " << pcDonneesRecues << endl;
	return true;
}

//cette fonction est appelée dès que la connexion est coupée
HELKSLOT FermetureHSocket()
{
	cout << "La connexion vient d'etre coupee" << endl;
	return true;
}

//gestion des erreurs
HELKSLOT ErreurHSocket(const char * pcErreurDescr, const ulong uErrNum)
{
	cout << "\7Erreur n " << uErrNum << " :\r\n" << pcErreurDescr << endl;
	return true;
}

//on peut afficher la progression d'un envoi plus gros que la taille par défaut du buffer d'envoi (100 octets ici)
HELKSLOT EnvoiEnCours(ulong uEnvoyes, ulong uRestants)
{
	cout << "Progression : " << uEnvoyes << " octets envoyes + " << uRestants << " octets restants" << endl;
	return true;
}

//l'envoi est fini (utile pour des paquets assez gros)
HELKSLOT FinEnvoi()
{
	cout << "L'envoi est terminé" << endl;
	return true;
}

Conclusion :


Il semble rester quelques bugs, notamment celui ci:
- il est possible (parfois seulement) d'envoyer des messages apres deconnexion, ce qui évidemment genere un message d'erreur
Ceci dit, la classe mériterait d'être encore un peu améliorée (cf interactions threads et objet HelkSock...), et la gestion des erreurs devrait être un peu (beaucoup) améliorée

je suis ouvert à toute suggestion, remarque ou demande éventuelle...

a++ et bonne prog à tous
Helkanen

ps: comment peut-on connaitre le port local sur lequel le socket s'est branché (écoute ou connexion) ?

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
368
Date d'inscription
jeudi 13 mars 2003
Statut
Membre
Dernière intervention
27 janvier 2010
1
Non y'en a un qui t'a mis 10 et un autre 8 !
Messages postés
54
Date d'inscription
mardi 24 décembre 2002
Statut
Membre
Dernière intervention
9 juin 2004

au fait, je sais pas qui m'a mis 9/10 mais je lui en suis bien reconnaissant ;p
Messages postés
54
Date d'inscription
mardi 24 décembre 2002
Statut
Membre
Dernière intervention
9 juin 2004

ben a vrai dire j'ai pas encore trop utilise ma classe ( :S )
en fait j'ai meme pas essayé d'utiliser plusieurs HelkSock en meme temps...
en tout cas, ca me fait plaisir de savoir que ma classe peut etre utile à qqn (pour une fois !)

faudra que je me remette a travailler sur la source (elle mériterait encore qqes ameliorations) mais la g pas vraiment le temps (pfff bac blanc)
si jamais tu trouves la solution, préviens moi en je ferai le nécessaire

a++ et bonne prog
Helkanen

ps : comme je l'ai déjà dit : minuit c pas une heure (hehe, pour moi c souvent pareil :p )
Messages postés
4
Date d'inscription
mercredi 5 février 2003
Statut
Membre
Dernière intervention
26 mai 2008

Salut ; très pratique tes sources, merci ;
par contre j'ai un petit soucis.
Je suis sous VC++ .NET et je n'arrive qu'à avoir 2 clients maxi qui se connectent..ensuite je suis obligé de relancé l'application, sinon plus rien ne se passe et sa commence à ramer.
Je n'ai pas inséré dans mon code la ligne srand(time(0)); et je ne traite pas encore les envois de données.
As-tu déja rencontré ce probleme ?

Merci d'avance !
Messages postés
54
Date d'inscription
mardi 24 décembre 2002
Statut
Membre
Dernière intervention
9 juin 2004

merci bcp pour ce commentaire...
en effet le mieux serait de la rendre portable...
mais contrairement à ce qu'on dit sur Linux (stabe et tout) j'ai eu plein de problemes en l'installant sur mon pc... (c'est bien dommage)
donc je ne maîtrise pas vraiment cet OS et encore moins la programmation LINUX, mais cela ne saurait tarder... ;)
elle mérite encore d'être améliorée, notamment pour implémenter les fonctions gethostname... et pour récupérer les IP locales et le port local ouvert (si possible)

a++ et bonne prog à toi aussi (3h51 c pas une heure ! :p)
helkanen
Afficher les 6 commentaires

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.