IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Quelle classe ou fonction utiliser pour envoyer des messages par TCP IP


Sujet :

C++

  1. #21
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Pas tout à fait : traverser (logiciellement) la couche TCP est plus long que traverser la couche UDP : pas de machine à états, pas de fenêtres, pas de fragmentation, pas de connexion trois points, etc.

    Attention : soyons bien d'accord, là, on parle de gain très légers (de l'ordre de la microseconde au mieux pour chaque paquet). Sur UN envoi, c'est difficilement mesurable. Sur un transfert soutenu, c'est mesurable, voire significatif.
    On est bien d'accord: on parle d'un temps pour traverser la stack qui est totalement négligeable ; la granularité de l'ordonnanceur pour un OS non temps-réel (ce qui me semble être ton cas puisque tu parles de 'DLL') anihilera toute différence, de même que tout code dans ton développement un poil moins optimisé que ce qui aurait pu l'être.

    Donc l'UDP n'aidera en rien ici à 'gagner du temps'. C'est ce que je voulais souligner, car ce genre de mythe "TCP est plus lent qu'UDP" (dans le sens SENSIBLEMENT plus lent) est un mythe qui a malheureusement la vie (trop) dure sur le web.

    Citation Envoyé par bacelar Voir le message
    nouknouk, tes statistiques prennent-t-elles en compte le cout d'établissement et de fermeture de connexion, le problème des démarrage progressif (Nagles) etc... ?
    On parle évidemment d'une connexion déjà établie, donc une comparaison dans le cadre d'un fonctionnement 'normal' de chacun des protocoles (ie. tels qu'ils ont été prévus). Et dans ce cas là, la différence est nulle.

    Citation Envoyé par Mac LAK Voir le message
    [...]les connexions TCP/IP, situées bien plus haut dans le modèle OSI, et qui peuvent "survivre" sans connexion physique pendant un petit moment (classiquement, trente secondes est un timeout courant).
    +10. Au mieux, tu pourras détecter au moyen de fonction bas niveau (non relatives au sockets) la perte de connexion sur le premier lien entre ton ordi et l'équipement suivant (switch, ...). En aucun cas, tu ne pourras 'monitorer' le serveur à l'autre bout de la connexion.
    Les deux seules solutions sont:
    - soit le programme du serveur qui envoie un ACK à chaque donnée reçue
    - soit un mécanisme de 'keepalive' implémenté avec une fréquence bien supérieure aux 'standards' (genre 200ms au lieu des 30s habituelles).

    Citation Envoyé par 3DArchi Voir le message
    J'avais un vague souvenir de ce genre: send retourne dès que les données sont transmises au buffer de la stack et non à la réception du ACK. Donc une partie de son problème de départ (celle que je souligne) pourrait se traiter en jouant sur la taille des buffers d'émission/réception.
    Je ne vois pas en quoi jouer sur le buffer d'émission changera quoi que ce soit, à moins que les quantités de données soient telles que la liaison ne supporte plus la charge.
    La bonne solution me semble être la désactivation de l'algo de Nagle sur la socket qui générera un paquet à chaque appel 'write' sur ta socket.

    L'idéal serait d'avoir plus de données sur les contraintes imposées. Mais si on se réfère à ce que j'ai pu glaner:

    - on a un réseau filaire local (supposons du 100Mbits)
    - on a une quantité de données 'raisonnable' puisqu'aucun souci de débit n'a été mentionné
    - on veut un temps d'exécution de 100ms maximum de la fonction de la DLL.
    - on préfère faire du synchrone pour l'appel de la fonction de la DLL (elle retourne le résultat de l'envoi).

    Dans ce cas là, les contraintes ne sont finalement pas bien fortes. On peut surtout compter sur une latence très faible d'une réseau Ethernet uniquement filaire (moins de 5ms de RTT).

    Donc on a 20 fois plus de temps (100ms / 5ms) que le temps 'réseau' nécessaire pour envoyer un paquet et recevoir une sorte d'ACK que le serveur émterrait à chaque réception de paquet.
    En d'autres termes, ça veut dire que même si on a une perte de paquet de temps en temps (voir même 10 de fois de suite, ce qui n'arrivera jamais), la marge est bien assez large pour laisser le temps à la couche TCP de renvoyer le paquet perdu et attendre un message d'ACK (de niveau applicatif au sens OSI) du serveur.

    Donc le plus simple me semble de ne pas s'encombrer outre mesure:

    - une connexion en TCP, algo de Nagle désactivé (important)

    - on établit une fois pour toutes la connexion avec le serveur au départ.

    - chaque fois qu'on veut envoyer une donnée, on utilie le canal TCP; à la réception de la donnée, le serveur envoie à son tour un message d'ACK.

    - dès le ACK reçu côté client, la DLL retourne le résultat.

    - on implémente un timeout de 100ms. Passé le délais, la DLL retourne une erreur 'serveur indisponible ou réseau surchargé (ou liaison de daube)'.

    Ca prendra 15 minutes à implémenter et ça couvrira l'ensemble des contraintes énumérées. Pas besoin de vouloir s'ennuyer à faire quoi que ce soit de plus complexe amha.

  2. #22
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par nouknouk Voir le message
    +10. Au mieux, tu pourras détecter au moyen de fonction bas niveau (non relatives au sockets) la perte de connexion sur le premier lien entre ton ordi et l'équipement suivant (switch, ...). En aucun cas, tu ne pourras 'monitorer' le serveur à l'autre bout de la connexion.
    Pas par ce biais en tout cas, en effet. On peut toujours avoir un "keep-alive" via des requêtes ICMP ou UDP, mais c'est un tout autre registre et, surtout, ça commence à sentir l'usine à gaz si l'on en arrive à un tel point...

  3. #23
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Pas par ce biais en tout cas, en effet. On peut toujours avoir un "keep-alive" via des requêtes ICMP ou UDP, mais c'est un tout autre registre et, surtout, ça commence à sentir l'usine à gaz si l'on en arrive à un tel point...
    Désolé, j'ai édité mon post entre temps pour le compléter. Effectivement on peut avoir un mécanisme de keep-alive, mais au final ça ne sert à pas grand chose: quelle que soit la fréquence du keep-alive choisie, il se pourra très bien que le serveur soit 'tombé' entre le dernier 'keep alive' et l'appel de la fonction de la DLL.
    On ne ferait que diminuer (mais on ne le supprime pas) la probabilité de renvoyer un résultat erroné en sortie de fonction DLL (genre "paquet OK" alors qu'en réalité les serveur était 'tombé' et le paquet jamais réçu).

    Le mécanisme d'ACK au niveau logiciel est quand à lui sûr (sauf cas exceptionnel) et beaucoup plus immédiat à implémenter.

  4. #24
    Nouveau membre du Club

    Homme Profil pro
    Ing. dev
    Inscrit en
    Septembre 2009
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing. dev
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2009
    Messages : 29
    Points : 29
    Points
    29
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par nouknouk Voir le message
    Donc le plus simple me semble de ne pas s'encombrer outre mesure:

    - une connexion en TCP, algo de Nagle désactivé (important)
    - on établit une fois pour toutes la connexion avec le serveur au départ.
    - chaque fois qu'on veut envoyer une donnée, on utilie le canal TCP; à la réception de la donnée, le serveur envoie à son tour un message d'ACK.
    - dès le ACK reçu côté client, la DLL retourne le résultat.
    - on implémente un timeout de 100ms. Passé le délais, la DLL retourne une erreur 'serveur indisponible ou réseau surchargé (ou liaison de daube)'.
    Yes c'est exactement ce que j'aimerais faire mais il y a un problème, mon serveur ne me répond pas, c'est une applic achetée ou je ne peux rien faire. Il faut que je puisse lire l'ACK de la couche TCP.

    Citation Envoyé par nouknouk Voir le message
    Ca prendra 15 minutes à implémenter et ça couvrira l'ensemble des contraintes énumérées. Pas besoin de vouloir s'ennuyer à faire quoi que ce soit de plus complexe amha.
    Quelles classes, fonctions, ... est ce que tu utilise pour faire ça ?

    Citation Envoyé par Mac LAK Voir le message
    Pas par ce biais en tout cas, en effet. On peut toujours avoir un "keep-alive" via des requêtes ICMP ou UDP, mais c'est un tout autre registre et, surtout, ça commence à sentir l'usine à gaz si l'on en arrive à un tel point...
    Jeudi passé en faisant des recherches sur le net je suis tombé sur un article qui parlait de faire un keep-alive avec l'envoi d'un message TCP ne contenant aucune donnée. Est ce que ça serais utilisable ?

  5. #25
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par lesteph Voir le message
    Yes c'est exactement ce que j'aimerais faire mais il y a un problème, mon serveur ne me répond pas, c'est une applic achetée ou je ne peux rien faire. Il faut que je puisse lire l'ACK de la couche TCP.
    Effectivement, j'aurais du relire avec plus d'attention tes posts précédents

    Tu as une solution très simple à implémenter pour palier à ce souci: un petit logiciel jouant le rôle de proxy que tu intercales entre le serveur à contacter et la DLL qui émet les messages.

    Concrètement, la communication ne se fera pas entre ta DLL et le serveur directement, mais entre ta DLL est un petit programme (à toi) qui tournera en local sur la machine hébergeant le serveur: la DLL est exécutée sur le poste client ; le 'proxy' s'exécute quant à lui sur la même machine 'physique' que le 'serveur' auquel la DLL doit envoyer ses messages.

    Encore plus conrètement:

    - ta DLL (côté client donc) envoie un message via une connexion TCP à ton proxy.

    - le proxy reçoit le message, et le frowarde vers l'appli serveur vi une connexion TCP mais cette fois locale à la machine (connexion utilisant le localhost).

    - si problème de réception côté serveur ou connexion fermée prématurément, ton proxy étant en localhost, il va être notifié de la chose quasi instantanément.

    - le proxy renvoie le résultat au client (la DLL): ACK ou erreur.

    - la DLL reçoit le résultat et sort de ta fonction d'envoi.

    Quelles classes, fonctions, ... est ce que tu utilise pour faire ça ?
    Tout dépend de ton environnement (notamment OS(es), version(s) supportées, ...) et de tes contraintes (lib externe autorisée, ...).

    Jeudi passé en faisant des recherches sur le net je suis tombé sur un article qui parlait de faire un keep-alive avec l'envoi d'un message TCP ne contenant aucune donnée. Est ce que ça serais utilisable ?
    Amha, tu vas galérer 10x plus pour un résultat plus incertain: rien ne te garantira qu'entre le dernier keepalive reçu et le moment où tu envoies le message, le serveur est toujours accessible (crash serveur, coupure réseau, ...).

  6. #26
    Nouveau membre du Club

    Homme Profil pro
    Ing. dev
    Inscrit en
    Septembre 2009
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing. dev
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2009
    Messages : 29
    Points : 29
    Points
    29
    Billets dans le blog
    1
    Par défaut
    Bin chui déçu moi qui croyais que j'aurais pu utiliser l'ACK de la couche TCP simplement, bon chui p'être un peu naif des fois...

    Yes ta solution est claire, me conviens parfaitement et parait assez simple a implémenter.

    Citation Envoyé par nouknouk Voir le message
    Tout dépend de ton environnement (notamment OS(es), version(s) supportées, ...) et de tes contraintes (lib externe autorisée, ...).
    J'utilise l'outil de développement Builder C++ 2007 et l'application côté client et serveur tourne sous Windobe XP. P'être dans quelque temps le client devra être sur Vista (ou 7) mais... c'est pas pour demain.

  7. #27
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 152
    Points : 12 260
    Points
    12 260
    Par défaut
    Je ne vois pas pourquoi ne pas utiliser les fonctionnalités offerte par la stack TCP/IP.
    http://msdn.microsoft.com/en-us/libr...51(VS.85).aspx

    Pas testé mais je ne pense pas que cela puisse contenir des surprises.

  8. #28
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par lesteph Voir le message
    Bin chui déçu moi qui croyais que j'aurais pu utiliser l'ACK de la couche TCP simplement, bon chui p'être un peu naif des fois...
    Les deux raisons principales qui me paraisent à l'origine du fait de ne pas pouvoir récupérer l'ACK d'un paquet envoyé:

    - le protocole TCP n'envoie pas (forcément) un ACK par 'paquet' reçu (mais un ACK pour une quantité de données pouvant correspondre à plusieurs 'paquets' émis). Tu as en effet la notion de 'fenêtre glissante' ('window' dans les articles techniques anglais) qui fait que l'émetteur a le droit d'envoyer plusieurs 'paquets' à la suite sans devoir à chaque fois attendre l'ACK du 'paquet' précédent, ceci pour améliorer les délais et la bande passante utilisée.

    - le protocole TCP est un protocole destiné à gérer la transmission d'un flux continu de données, pas un protocole qui gère des données paquets par paquets. La mécanique interne du protocole (et les équipements intermédiaires entre la source et la destination) a en effet toute latitude de fragmenter/regrouper des paquets de données pour rendre la transmission plus efficiente. A partir de là, puisque la notion de 'paquet de données' n'existe pas, l'existence de la notion d'ACK pour un paquet de données est compromise

    J'utilise l'outil de développement Builder C++ 2007 et l'application côté client et serveur tourne sous Windobe XP. P'être dans quelque temps le client devra être sur Vista (ou 7) mais... c'est pas pour demain.
    Je ne pourrai pas t'aider alors, sauf à dire qu'il existe une implémentation des 'sockets standard' relativement multi-plateforme et bien assez utilisée pour trouver de nombreux articles sur le sujet, dont celui-là

  9. #29
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par bacelar Voir le message
    Je ne vois pas pourquoi ne pas utiliser les fonctionnalités offerte par la stack TCP/IP.
    Parce que comme dit précédemment, la notion de keepalive ne garantira pas que le message a effectivement été reçu côté serveur sauf à mettre une période de keepalive sensiblement inférieure (50% maxi) au délai maximum imposé (ici 100ms).

    Et dans ce cas, on se retrouve avec un keepalive tellement faible qu'on va générer un traffic réseau 'pour rien' (dans le sens où une solution bien plus efficiente existe et donne finalement plus de garanties).

  10. #30
    Nouveau membre du Club

    Homme Profil pro
    Ing. dev
    Inscrit en
    Septembre 2009
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing. dev
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2009
    Messages : 29
    Points : 29
    Points
    29
    Billets dans le blog
    1
    Par défaut
    Par manque de temps j'ai encore simplifié la chose... je ferai mieux plus tard...

    Je me base uniquement sur l'établissement de la connexion. Si la connexion est OK c'est qu'il n'y a aucun problème, que mon serveur la acceptée et qu'il est à l'écoute. Donc pas de câble débranché, de switch KO, de serveur planté ou...

    Juste après j'envoie mes données. Bien sur il y a un risque qu'il y ait un problème entre l'établissement et l'envoi, mais sur les quelques micro-secondes qu'il y a... je pense que c'est totalement négligeable

    J'ai fait des essais et il arrive quelques fois que le temps établissement de la connexion soit entre 100 et 200ms, sinon il est bien inférieur à 100ms.

    J'ai utilisé la classe TTcpClient en socket non bloquante. Voici le bout de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    	// Creat the TCP connection
    	ClientTCP = new TTcpClient(NULL);
     
    	if( ClientTCP == NULL )
    		return -2 ;
     
    	ClientTCP->BlockMode = bmNonBlocking ;
    	ClientTCP->RemoteHost = Host ;
    	ClientTCP->RemotePort = IntToStr(Port);
     
    	// Start connect timer
    	Time0 = GetTickCount();
     
    	// Open Connection
    	ClientTCP->Open();
     
    	// Wait than connection is etablished
    	do{
     
    		Select = ClientTCP->Select( &ReadOK, &WriteOK, &Flag, 25);
    		TimeElapsed = GetTickCount() - Time0 ;
     
    		if(TimeElapsed > Timeout ){
    			ClientTCP->Close();
    			delete ClientTCP ;
    			return -3 ;
    		}
    	}
    	while( !( (Select==true)&&(WriteOK==true)&&(Flag==false) ) );
     
    	// Send Data
    	ClientTCP->Sendln( Msg, "\r" );
     
    	ClientTCP->Close();
    	delete ClientTCP ;
     
    	return 1 ;
    	}
    Merci à tous pour vos commentaires

  11. #31
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 152
    Points : 12 260
    Points
    12 260
    Par défaut
    Si vous faites une connexion pour chaque message, vous aurez des performances calamiteuses.

  12. #32
    Nouveau membre du Club

    Homme Profil pro
    Ing. dev
    Inscrit en
    Septembre 2009
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing. dev
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2009
    Messages : 29
    Points : 29
    Points
    29
    Billets dans le blog
    1
    Par défaut
    Comme je l'ai noté, je ferai mieux un peu plus tard, d'autres priorités sont apparues...

    Et surtout c'est la solution la plus simple que j'ai trouvé sans besoin d'écrire des dizaines de lignes de code.
    Mais si il y a d'autres solutions aussi simple et qui s'approche plus des contraintes de bases, je suis preneneur...

    Si vous faites une connexion pour chaque message, vous aurez des performances calamiteuses
    Les performances ne sont pas si calamiteuses puisques selon mes tests le temps de connexion est quelques fois entre 100 et 200ms mais en général il est bien en dessous de 100ms. Bon je pense que le cash de Windobe y est pour quelque chose.

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. [MySQL] info pour envoyer des données par mail
    Par boubourse92 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 30/01/2008, 13h04
  2. [C++] quelle structure de donnée utiliser pour stocker des vertices ?
    Par johnnyjohnny dans le forum Développement 2D, 3D et Jeux
    Réponses: 14
    Dernier message: 14/07/2007, 21h44
  3. formulaire pour envoyer des messages.
    Par cyrilmarc dans le forum Langage
    Réponses: 2
    Dernier message: 22/11/2006, 21h15
  4. [Mail] Codage d'une page pour envoyer des messages.
    Par cyrilmarc dans le forum Langage
    Réponses: 5
    Dernier message: 21/11/2006, 21h53
  5. Réponses: 4
    Dernier message: 28/03/2005, 19h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo