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

SL & STL C++ Discussion :

Quelle classe STL pour un simple flux réseau ?


Sujet :

SL & STL C++

  1. #21
    Membre averti
    Inscrit en
    Avril 2006
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 24
    Par défaut
    C'est bien entendu louable de déclarer des fonctions dangereuses et d'en promouvoir des versions sécurisées, cependant dans ce cas, je me demande ce que leur version apporte de plus. Je considère recevoir deux fois la même information : une longueur de tableau à remplir, et un nombre de caractères à fournir, je ne vois vraiment pas de grande différence (d'ailleurs je n'utilise qu'une valeur de longueur, le minimum des deux) : la longueur du tableau est normalement la taille à remplir. Mais si je me trompe corrigez moi

  2. #22
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Le deuxième paramètre est la taille du buffer, qui peut être différente de _Count. La méthode vérifie elle-même s'il y a assez de place dans le buffer.

  3. #23
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Citation Envoyé par Miles
    L'objectif est de sécuriser au maximum les fonctions pour éviter des dépassement de mémoire, et autres. Pour une fois que Microsoft fait ce qu'il dit - ie promouvoir la sécurité - on leur tape dessus en disant qu'ils veulent faire leur propre standard
    Ils VEULENT faire leur propre standard. Sinon, ils auraient implémenté la fonction snprintf() du standard C99 au lieu de faire leur sprintf_s...
    (sans parler de fopen_s qui ne sert absolument à rien, et de strtok_s qui est une pâle copie de strtok_r() avec un autre nom...)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #24
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Pour le standard C99, je ne dis pas, peut-être. En revanche pour le standard C++, basé sur le C89, ils ont raison d'aller plus loin, d'autant qu'ils ont des pointures dans l'équipe de développement de ce compilateur C++. Pour le C99, je ne sais pas pourquoi ils ne l'ont pas implémentée. De toute manière, VS2005 n'est pas un compilateur C99, mais encore C89, et ça se voit bien.

  5. #25
    Membre averti
    Inscrit en
    Avril 2006
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 24
    Par défaut
    Bien, je crois que je suis arrivé à quelque chose de correct avec mes flux ! J'ai lu le chapitre correspondant dans Standard C++ IOStreams and Locales, vraiment un bon bouquin.

    Voici mon code, je vous épargne les include et compagnie, pensez juste à inclure <streambuf> et <iostream>. Il manque aussi quelques opérateurs de portée globale, et j'ai un petit souci de protocole que je vous détaillerais plus bas. Cependant, cette solution de flux sans buffer est fonctionnelle :
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    class SocketStreamBuffer : public std::streambuf
    {
    public:
    	SocketStreamBuffer(SOCKET inSocket);
     
    protected:
     
    	virtual int_type overflow (int_type c);
    	virtual std::streamsize xsputn (const char_type *buf, std::streamsize len);
     
    	virtual int_type underflow ();
    	virtual int_type uflow ();
    	virtual int_type pbackfail (int_type c);
     
    #ifdef WIN32
    	virtual std::streamsize _Xsgetn_s (char_type *buf, std::streamsize len, std::streamsize count);
    #else // UNIX
    	virtual std::streamsize xsgetn (char_type *buf, std::streamsize len);
    #endif // WIN32
     
    private:
    	// The socket to  read from / write to
    	SOCKET m_Socket;
     
    	// One character buffer
    	char_type m_charBuf;
    	bool      m_takeFromBuf;
     
    	// Sockets select variables
    	fd_set  m_socketSet;
    	timeval m_zeroTimeOut;
     
    	// Prohitbit copying and assignment
    	SocketStreamBuffer(const SocketStreamBuffer&);
    	SocketStreamBuffer& operator = (const SocketStreamBuffer&);
    };
     
    SocketStreamBuffer::SocketStreamBuffer(SOCKET inSocket)
    	: m_Socket(inSocket), m_takeFromBuf(false)
    {
    	FD_ZERO(&m_socketSet);
    	FD_SET(m_Socket, &m_socketSet);
    	m_zeroTimeOut.tv_sec  = 0;
    	m_zeroTimeOut.tv_usec = 0;
    }
     
    SocketStreamBuffer::int_type SocketStreamBuffer::overflow (SocketStreamBuffer::int_type c)
    {
    	int nsent;
     
    	if ( c != EOF )
    	{
    		int blockState;
    		SocketStreamBuffer::char_type tosend = static_cast<SocketStreamBuffer::char_type>(c);
     
    		nsent = send(m_Socket, &tosend, 1, 0);
     
    		if ( nsent != 1 )
    		{
    			throw SocketIOException("Unable to send data", send_error,
    			                        "SocketStreamBuffer::overflow", __FILE__, __LINE__);
    		}
    	}
     
    	return c;
    }
     
    std::streamsize SocketStreamBuffer::xsputn (const SocketStreamBuffer::char_type *buf, std::streamsize len)
    {
    	std::streamsize nsent;
     
    	nsent = send(m_Socket, buf, len, 0);
    	if ( nsent != len )
    	{
    		throw SocketIOException("Unable to send data", send_error,
    		                        "SocketStreamBuffer::xsputn", __FILE__, __LINE__);
    	}
     
    	return nsent;
    }
     
    SocketStreamBuffer::int_type SocketStreamBuffer::underflow ()
    {
     
    	if ( !m_takeFromBuf )
    	{
    		int nread, blockState;
    		SocketStreamBuffer::char_type car;
     
    		// Test if we should receive data
    		blockState = select(0, &m_socketSet, NULL, NULL, &m_zeroTimeOut);
     
    		if ( blockState != 1 )
    		{
    			// Nothing to read, return EOF
    			m_charBuf = EOF;
    		}
    		else
    		{
    			// Read a new character and place it into the buffer
    			nread = recv(m_Socket, &car, 1, 0);
    			if ( nread == -1 )
    			{
    				throw SocketIOException("Unable to receive data", receive_error,
    										"SocketStreamBuffer::underflow", __FILE__, __LINE__);
    			}
    			else if ( nread == 0 )
    			{
    				// Nothing to read, return EOF
    				m_charBuf = EOF;
    			}
    			else
    			{
    				m_takeFromBuf = true;
    				m_charBuf = static_cast<SocketStreamBuffer::int_type>(car);
    			}
    		}
    	}
     
    	return m_charBuf;
    }
     
    SocketStreamBuffer::int_type SocketStreamBuffer::uflow ()
    {
     
    	if ( !m_takeFromBuf )
    	{
    		int nread, blockState;
    		SocketStreamBuffer::char_type car;
     
    		// Test if we should receive data
    		blockState = select(0, &m_socketSet, NULL, NULL, &m_zeroTimeOut);
     
    		if ( blockState != 1 )
    		{
    			// Nothing to read, return EOF
    			m_charBuf = EOF;
    		}
    		else
    		{
    			// Read a new character and place it into the buffer
    			nread = recv(m_Socket, &car, 1, 0);
    			if ( nread == -1 )
    			{
    				throw SocketIOException("Unable to receive data", receive_error,
    										"SocketStreamBuffer::underflow", __FILE__, __LINE__);
    			}
    			else if ( nread == 0 )
    			{
    				// Nothing to read, return EOF
    				m_charBuf = EOF;
    			}
    			else
    			{
    				m_charBuf = static_cast<SocketStreamBuffer::int_type>(car);
    			}
    		}
    	}
    	else
    	{
    		// uflow steps forward
    		m_takeFromBuf = false;
    	}
     
    	return m_charBuf;
    }
     
    SocketStreamBuffer::int_type SocketStreamBuffer::pbackfail (SocketStreamBuffer::int_type c)
    {
    	if ( !m_takeFromBuf )
    	{
    		// Put the character back in the buffer
    		if ( c != EOF )
    		{
    			m_charBuf = c;
    		}
     
    		m_takeFromBuf = true;
    		return m_charBuf;
    	}
    	else
    	{
    		return EOF;
    	}
    }
     
    #ifdef WIN32
    std::streamsize SocketStreamBuffer::_Xsgetn_s (SocketStreamBuffer::char_type *buf, std::streamsize len, std::streamsize count)
    #else // UNIX
    std::streamsize SocketStreamBuffer::xsgetn    (SocketStreamBuffer::char_type *buf, std::streamsize len)
    #endif // WIN32
    {
    	std::streamsize nread = 0;
    #ifdef WIN32
    	len = min(len, count);
    #endif
     
    	if (len > 0)
    	{
    		nread = recv(m_Socket, buf, len, 0);
    		if ( nread == -1 )
    		{
    			throw SocketIOException("Unable to receive data", receive_error,
    									"SocketStreamBuffer::underflow", __FILE__, __LINE__);
    		}
    	}
     
    	return nread;
    }
    Le problème avec cette solution est d'ordre technique : apparemment, les sockets TCP demandent d'avoir une socket en écoute avant de pouvoir envoyer des données, ce qui rend complexe la gestion des envois de rafales de caractères (beaucoup d'envois d'un seul caractère). Une solution avec buffer serait plus judicieuse, elle est en cours de développement , mais elle demande encore réflexion (quand faire un flush, le rendre implicite ou explicite, comment être sûr que le client écoute, ...).

    Voilà, merci à tous, et j'espère que ce petit exemple vous sera utile !

  6. #26
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Je ne suis pas un spécialiste, mais il me semble qu'il faut que tu redéfinisses la fonction sync() de streambuf pour y envoyer ton buffer ; apparemment elle est appelée par le flux à chaque flush (std::flush ou std::endl), ce qui me parait pas mal comme moment pour balancer la sauce sur tes sockets (à moins que tu ne veuilles faire un truc très performant, auquel cas effectivement il vaudra mieux que l'envoi soit contrôlé plus finement).

  7. #27
    Membre averti
    Inscrit en
    Avril 2006
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 24
    Par défaut
    En réalité, cette fonction ne doit être surchargée que dans le cas d'un Streambuffer avec un réel buffer. Dans ce cas, il permet de remplir le buffer, mais dans mon cas très simple d'écriture synchrone, l'écriture est effectuée à chaque opération. Je suis cependant en train de me poser la question d'un buffer.

    Attention, il se peut que le code ci dessus ne fonctionne pas comme prévu, j'ai des comportement étranges d'exceptions d'allocation dans les opérations de mon objet flux lorsque l'archive Boost s'initialise, je vous en dirais plus si j'arrive à comprendre ces problèmes.

  8. #28
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Oui oui, ma réponse faisait bien suite à ta reflexion sur l'utilisation d'un buffer.

  9. #29
    Membre averti
    Inscrit en
    Avril 2006
    Messages
    24
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 24
    Par défaut
    Pour les opérations avec buffer, il faut effectivement surcharger sync et gérer le buffer dans toutes les autres fonctions au lieu d'écrire directement. Reste à gérer en plus tous les problèmes de synchronisation ...

    Il est à noter que l'exemple précédant ne fonctionne pas correctement lors d'une utilisation bidirectionnelle : instanciez deux objets, un pour l'écriture et l'autre pour la lecture

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

Discussions similaires

  1. Réponses: 11
    Dernier message: 27/09/2013, 13h02
  2. Quelle classes Java pour mon interface ?
    Par sitws dans le forum Débuter
    Réponses: 4
    Dernier message: 28/04/2011, 13h42
  3. Réponses: 6
    Dernier message: 26/06/2006, 10h29
  4. Réponses: 2
    Dernier message: 17/03/2006, 09h26
  5. [FPDF] Quelle classe pour produire des PDF simples ?
    Par boteha dans le forum Bibliothèques et frameworks
    Réponses: 6
    Dernier message: 03/11/2005, 22h55

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