Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Lecture fragmentee de binaires

29 réponses
Avatar
NaeiKinDus
Bonjour tout le monde !

Je planche actuellement sur un serveur web, et je dois "fragmenter"
l'envoi de mes donnees pour ne pas bloquer X clients lorsqu'un
telecharger un fichier... Disons en blocs de 5Ko. Neanmois, je n'y
arrive absolument pas, ma lecture plante avec un tellg qui renvoit -1
comme taille, et une concat qui foire, donc :(

Code:

ifstream fileStream;
unsigned int size;
char tmp[4096;]

fileStream.open(file.c_str(), ios_base::in | ios_base::binary); //file
est un string recuperee dans un autre endroit du code
cerr << "opened ? " << fileStream.is_open() << endl; // affiche 1
cerr << "good ? " << fileStream.good() << endl; // affiche 1
request.append("\r\nContent-Length: ");
fileStream.seekg(0, ios_base::end);
size = fileStream.tellg();
oss << size;
request.append(oss.str());
request += "\r\n";
request.append("Accept-Ranges: bytes\r\n");
request.append("Connection: keep-alive\r\n\r\n"); // Separation du
header et du body par une paire de "\r\n"
if (*idx > 0){ //*idx est un pointeur sur un int qui permet de
reprendre la lecture la ou on l'avait laissee...
cerr << "clearing request\n";
request.clear(); // si on passe ici, on a pas besoin de header (en
theorie)
fileStream.seekg(*idx);
}
else
fileStream.seekg(0, ios_base::beg);
long pos = (long)fileStream.tellg() - *idx; // Je souhaitais pouvoir
me placer dans mon tmp pour mettre le '\0', mais tellg me renvoit
toujours -1 :(
cerr << "opened ? " << fileStream.is_open() << endl; // renvoi 1
cerr << "good ? " << fileStream.good() << endl; // renvoi 1
fileStream.read(tmp, 4095); // char tmp[4096]... 1 octet pour mettre
le '\0' (habitude unix... bonne ou pas ?)
cerr << "tellg: " << (long)fileStream.tellg() << endl; // renvoi -1
cerr << "idx: " << *idx << endl; // renvoi 0
cerr << "pos: " << pos << endl; // renvoi -1
//tmp[pos] = '\0'; // donc logiquement ca pete ici
*idx = (long)fileStream.tellg(); // je garde en memoire la valeur de
lecture pour reprendre plus tard
if (*idx == size){ // si le fichier est complet, on met idx a -1 pour
que la fonction appellante close la socket.
cerr << "Reseting *idx to -1";
*idx = -1;
request.append(tmp);
request += "\r\n";
}
else
request.append(tmp);



Merci a tous :)

10 réponses

1 2 3
Avatar
James Kanze
On Apr 2, 12:27 pm, "NaeiKinDus" wrote:

Je planche actuellement sur un serveur web, et je dois "fragmenter"
l'envoi de mes donnees pour ne pas bloquer X clients lorsqu'un
telecharger un fichier... Disons en blocs de 5Ko. Neanmois, je n'y
arrive absolument pas, ma lecture plante avec un tellg qui renvoit -1
comme taille, et une concat qui foire, donc :(

Code:

ifstream fileStream;
unsigned int size;
char tmp[4096;]

fileStream.open(file.c_str(), ios_base::in | ios_base::binary); //file
est un string recuperee dans un autre endroit du code
cerr << "opened ? " << fileStream.is_open() << endl; // affiche 1
cerr << "good ? " << fileStream.good() << endl; // affiche 1
request.append("rnContent-Length: ");
fileStream.seekg(0, ios_base::end);
size = fileStream.tellg();


Il y a deux problèmes, associés, ici. Pour commencer, tellg ne
renvoie pas un unsigned int. Ce n'est même pas garanti,
d'ailleurs, que le type qu'il renvoie puisse être converti en
type entier. Aussi, au moins sur les systèmes que je connais
(Solaris, Linux), la taille d'un fichier ne tient pas sur un
unsigned int.

Que ça plaise ou non, je crois que si tu veux savoir la taille,
il vaut mieux utiliser les requêtes système. (Et une fois que tu
as perdu la portabilité à cause de ça, autant que faire utiliser
les requêtes système pour lire le fichier aussi.)

oss << size;


C'est quoi, oss ? (D'après l'utilisation, j'imagine que c'est
un ostringstream, mais je n'en vois pas la définition.)

request.append(oss.str());
request += "rn";
request.append("Accept-Ranges: bytesrn");
request.append("Connection: keep-alivernrn"); // Separation du
header et du body par une paire de "rn"
if (*idx > 0){ //*idx est un pointeur sur un int qui permet de


C'est quoi, idx ? Où est-ce qu'il a été initialisé ?

reprendre la lecture la ou on l'avait laissee...
cerr << "clearing requestn";
request.clear(); // si on passe ici, on a pas besoin de header (en
theorie)
fileStream.seekg(*idx);}

else
fileStream.seekg(0, ios_base::beg);
long pos = (long)fileStream.tellg() - *idx; // Je souhaitais pouvoir
me placer dans mon tmp pour mettre le '', mais tellg me renvoit
toujours -1 :(


Si tellg() renvoie toujours -1, c'est qu'il y a eu une erreur
auparavant dans le flux.

cerr << "opened ? " << fileStream.is_open() << endl; // renvoi 1
cerr << "good ? " << fileStream.good() << endl; // renvoi 1
fileStream.read(tmp, 4095); // char tmp[4096]... 1 octet pour mettre
le '' (habitude unix... bonne ou pas ?)


Ce n'est pas nécessaire avec read. Il ne s'agit pas du texte,
donc, il n'y a pas de ''.

cerr << "tellg: " << (long)fileStream.tellg() << endl; // renvoi -1
cerr << "idx: " << *idx << endl; // renvoi 0
cerr << "pos: " << pos << endl; // renvoi -1


De nouveau : c'est quoi pos ?

//tmp[pos] = ''; // donc logiquement ca pete ici
*idx = (long)fileStream.tellg(); // je garde en memoire la valeur de
lecture pour reprendre plus tard
if (*idx == size){ // si le fichier est complet, on met idx a -1 pour
que la fonction appellante close la socket.
cerr << "Reseting *idx to -1";
*idx = -1;
request.append(tmp);
request += "rn";}
else
request.append(tmp);


Il en manque des parties importantes. Mais je ne comprends pas
pourquoi toute cette complexité. Il n'y a que toi qui lit le
fichier, et tu le lis de façon séquentielle. Il n'y a donc
jamais besoin d'un seek. (Je crois qu'il y a des problèmes côté
request aussi. Si tu es en train d'envoyer du binaire, l'ajoute
de "rn" n'y va pas.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
NaeiKinDus
Desole des oublis, c'est que j'ai tire le code d'une fonction ( que je
n'ai maintenant plus, pour cause de modifications lourdes)...

oss est en effet un ostringstream, j'ai pris cette methode sur
developpez.com pour convertir les donnes en int...
Concernant tellg, au temps pour moi, c'est normalement un long...
Cependant, codant pour Windows, je n'ai trouve que cette maniere la de
connaitre la taille :(
Pour idx, c'est l'abreviation d'index, pour savoir ou en est la
lecture dans le fichier.
Concernant pos, je l'avais defini dans le code meme, pour le , mais
vu que c'est inutile, a zapper :)


Et enfin, pour la complexite, je m'explique : Je fais un serveur web,
donc si je devais rester bloque dans ma boucle pour l'envoi de donnees
vers un client, les autres clients geres par la thread seraient, eux,
bloques :(
A moins que je n'appelle une autre thread dediee a la lecture du
fichier ... ?
Avatar
Mathias Gaunard

Concernant tellg, au temps pour moi, c'est normalement un long...


Toujours pas non.
C'est fou cette difficulté que peuvent alors les gens pour lire une
référence.


A moins que je n'appelle une autre thread dediee a la lecture du
fichier ... ?


À moins que tu fasses des entrées/sorties asynchrones orientées événement ?

Avatar
NaeiKinDus
On 2 avr, 15:06, Mathias Gaunard wrote:

Concernant tellg, au temps pour moi, c'est normalement un long...


Toujours pas non.
C'est fou cette difficulté que peuvent alors les gens pour lire une
référence.


Non, non, je t'assure que j'en bouffe pas mal depuis le debut :)
Mais en l'occurence, et d'apres la MSDN:

"Return Value

A streampos type, corresponding to a long."

Apres je n'ai pas assez de connaissances et de capacites pour
contredire la msdn ^_^


A moins que je n'appelle une autre thread dediee a la lecture du
fichier ... ?


À moins que tu fasses des entrées/sorties asynchrones orientées é vénement ?


Euh... oui, possible, si je trouve a quoi ca correspond
"concretement" !

Merci pour les suggestions :)


Avatar
espie
In article ,
NaeiKinDus wrote:
On 2 avr, 15:06, Mathias Gaunard wrote:

Concernant tellg, au temps pour moi, c'est normalement un long...


Toujours pas non.
C'est fou cette difficulté que peuvent alors les gens pour lire une
référence.


Non, non, je t'assure que j'en bouffe pas mal depuis le debut :)
Mais en l'occurence, et d'apres la MSDN:

"Return Value

A streampos type, corresponding to a long."

Apres je n'ai pas assez de connaissances et de capacites pour
contredire la msdn ^_^



Il y a autre chose que la MSDN dans la vie !

En plus, ca se lit, quand meme, bon sang.

Ils te disent que le type de tellg, c'est une position dans un stream, et
que dans leur implementation, ca correspond souvent a un long
(mais ca c'est clairement non portable, ni meme garanti). Bon, ils
pourraient etre plus clair, mais ca se saurait, si
le MSDN en avait quoi que ce soit a foutre de la portabilite ailleurs
que sous windows.

Procure-toi une vraie doc complete.

La norme, elle, decrit:

pos_type tellg();

sans plus d'explications.

En cherchant un peu, on trouve la definition de pos_type dans
basic_streambuf. C'est donc un type qui est dependant de l'objet que tu
manipules... (defini en traits du type caractere qui t'interesse).

Les traits par defaut te donnent effectivement streampos pour char,
wstreampos pour wchar.

streampos *peut* etre implemente par un long.



Avatar
James Kanze
On Apr 2, 1:59 pm, "NaeiKinDus" wrote:
Desole des oublis, c'est que j'ai tire le code d'une fonction ( que je
n'ai maintenant plus, pour cause de modifications lourdes)...


N'empêche que si tu veux des informations, ça serait beaucoup
plus facile pour nous de t'en donner si tu présentais un petit
programme qui isole le problème et qui se compile.

oss est en effet un ostringstream, j'ai pris cette methode sur
developpez.com pour convertir les donnes en int...


C'est tout à fait comme ça qu'on fait. C'est d'ailleurs parce
que j'ai reconnu l'idiome que je me suis douté qu'il s'agissait
d'un ostringstream.

Concernant tellg, au temps pour moi, c'est normalement un long...


C'est un type défini par l'implémentation. Et ça ne peut pas
être un long, parce qu'en principe, il contient aussi des
informations sur la position dans un caractère composé
(multibyte, en anglais). Normalement, c'est un
std::fpos< mbstate_t >.

Il doit se convertir (implicitement ? je n'en suis pas sûr) en
type d'« offset » dans le flux. *Typiquement*, le type
d'offset et bien un type entier -- c'est un long long chez
moi -- mais la norme permet bien un type classe aussi. Et du
coup, ton affectation poserait un problème. (Réalistiquement, je
crois qu'elle pose un problème déjà. Parce qu'affecter un long
long à un int risque bien de perdre des informations.)

Cependant, codant pour Windows, je n'ai trouve que cette maniere la de
connaitre la taille :(


GetFileAttributesEx ne marche pas ? C'est ce qui me sert sous
Windows (et stat() sous Unix).

C'est un peu pénible qu'il me faut des fonctions différentes
selon le système d'exploitation, mais c'est le cas pour prèsque
tout ce qui concerne les attributes des fichiers.

Pour idx, c'est l'abreviation d'index, pour savoir ou en est la
lecture dans le fichier.


Mais c'est quoi, comme type de variable ? Et où est-ce qu'elle
est initialisée ?

Concernant pos, je l'avais defini dans le code meme, pour le , mais
vu que c'est inutile, a zapper :)

Et enfin, pour la complexite, je m'explique : Je fais un serveur web,
donc si je devais rester bloque dans ma boucle pour l'envoi de donnees
vers un client, les autres clients geres par la thread seraient, eux,
bloques :(
A moins que je n'appelle une autre thread dediee a la lecture du
fichier ... ?


Tu as plusieurs clients gérer par le même thread ? Moi,
j'aurais un client par thread. La solution classique dans les
serveurs, c'est de créer un thread pour chaque connexion, lors
de la connexion. (En fait, la solution classique dépend de
l'application. Si on peut répondre assez rapidement, sans
maintenir la connexion, on traite la connexion dans le thread
même, et l'application est mono-thread. Et si il n'y a pas
besoin que les connexions partagent des informations entre
elles, souvent, il est préférable de démarrer un noveau
processus pour chaque connexion, plutôt que simplement un
thread.)

De toute façon, je doute que ce soit le temps de lecture du
fichier qui pose un problème. Le temps d'écriture vers le
socket, en revanche, peut-être. C'est surtout les écritures vers
le socket qu'il faudrait saucissonner.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
James Kanze
On Apr 2, 4:25 pm, (Marc Espie) wrote:
In article ,

NaeiKinDus wrote:
On 2 avr, 15:06, Mathias Gaunard wrote:

Concernant tellg, au temps pour moi, c'est normalement un long...


Toujours pas non.
C'est fou cette difficulté que peuvent alors les gens pour lire une
référence.


Non, non, je t'assure que j'en bouffe pas mal depuis le debut :)
Mais en l'occurence, et d'apres la MSDN:

"Return Value

A streampos type, corresponding to a long."



Sauf que dans les en-têtes, je trouve :
typedef fpos<_Mbstatet> streampos;
C'est en fait un type classe, comme le veut la norme. Il se
convertit (implicitement) en streamoff, qui a type long. (Ce qui
me semble bizarre, parce que les longs, c'est du 32 bits, et les
fichiers sous Windows peut bien avoir plus de 2^32 octets.
Quand je fait GetFileAttributesEx, j'ai bien la taille dans le
WIN32_FIND_DATA, sur deux mots de 32 bits.)

Apres je n'ai pas assez de connaissances et de capacites pour
contredire la msdn ^_^


Il y a autre chose que la MSDN dans la vie !


Aussi, ce n'est pas vraiment ce que je lis comme référence C++.
(Je l'utilise bien comme référence pour l'API Windows,
évidemment.)

[...]
La norme,


Soyons honnête. La norme, ce n'est pas ce qu'il faut lire pour
apprendre le C++. Ni même comme référence, au moins de s'y
connaître bien.

elle, decrit:

pos_type tellg();

sans plus d'explications.


Si, il y a d'autres explications. À d'autres endroits. Si tu
rémontes, tu finiras par trouver que pos_type correspond à un
typedef dans char_traits, et que pour les flux classique, ce
typedef vaut une instantiation de fpos, qui lui aussi est
défini.

En cherchant un peu, on trouve la definition de pos_type dans
basic_streambuf. C'est donc un type qui est dependant de l'objet que tu
manipules... (defini en traits du type caractere qui t'interesse).

Les traits par defaut te donnent effectivement streampos pour char,
wstreampos pour wchar.

streampos *peut* etre implemente par un long.


Non. Il est obligatoirement un std::fpos<>. Il peut se convertir
implicitement en streamoff, et streamoff peut être implémenté
par un long. Seulement, ça n'a de sens aujourd'hui que si long a
64 bits ; sinon, tu as un petit problème avec des fichiers au
delà d'une certaine taille.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

streampos *peut* etre implemente par un long.


Je m'en suis pas sur du tout... de memoire, un std::streampos c'est
fpos<mbstate_t> et doit donc etre capable de stocker l'etat des conversions
d'encodage en plus de la position. Pratiquement, ce ne peut etre un long
qu'a condition de reduire les deplacements possibles ou de limiter les
etats.

Il n'y aurait pas eu quelque part une confusion avec streamoff?

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
NaeiKinDus
Très bien, veuillez m'excuser pour la confusion des genres, mais un
"corresponding to a long" veut dire que type == long... A tord semble
t il !
Je m'en vais corriger ça de suite.

Pour le petit programme isolant le soucis, j'en serais bien en peine
de réaliser ça car le soucis peut se trouver à pas mal d'endroits, et
prendree en compte les threads, les sockets, etc... dur.

Idx : long qui contient la position dans la lecture de fichier... A
changer donc par un streampos.

Pourquoi ne pas faire un thread / client ?
1°/ Ce programme est un projet d'études... et cette clause est
précisée dans le sujet !
2°/ Il semblerait que cela ne soit pas bon à fort taux de charge, avec
un ralentissement considérable du serveur...

GetFileAttributesEx : merci pour la fonction, je ne l'avais pas
trouvée :( (je m'étais borné à l'utilisation du tellg...)

Finalement, concernant les prototypes de fonctions, les mans & co,
auriez vous un site que vous considéreriez de "bien" ? (càd, mieux que
la msdn qui semble avoir quelques lacunes....)

Merci à tous !
Avatar
Mathias Gaunard

Sauf que dans les en-têtes, je trouve :
typedef fpos<_Mbstatet> streampos;
C'est en fait un type classe, comme le veut la norme. Il se
convertit (implicitement) en streamoff, qui a type long. (Ce qui
me semble bizarre, parce que les longs, c'est du 32 bits, et les
fichiers sous Windows peut bien avoir plus de 2^32 octets.
Quand je fait GetFileAttributesEx, j'ai bien la taille dans le
WIN32_FIND_DATA, sur deux mots de 32 bits.)


Pour une raison obscure, on est limité sous Windows dans la taille des
fichiers quand on utilise la bibliothèque standard C ou C++.

1 2 3