je me demande s'il existe un nombre d'octets limités sur un socket,
annoncé par un FD_READ, pour allouer ue taille fixe et suffisante a un
buffer de reception... ?
autre petite question sur un point pas clair :
je reçoit un FD_READ, et j'ai disons 3ko sur la socket qui attendent
d'etre reçus. 3ko sur un total de 10ko que mon serveur a envoyé.
je reçoit les données annoncées par le message avec ioctlsocket et
FIONREAD, qui m'indique la quté de donnée pouvant etre lues sur un seul
recv, disons que cette quté est inférieure aux 3ko présents...et
qu'elle est égale a...2ko
aurai-je un autre FD_READ pour le 1ko restant ? ou le prochain FD_READ
se produira-t-il lorsqu'un autre paquet de données arrivera sur la
socket ?
La séquence suivante n'est pas très bonne. Par caractère que tu reçois tu vas faire un appel à memcpy, memmove et realloc... c'est bon pour faire des tests mais en production on vire tout ça.
//copie d'un octet de recvbuf dans 'c' memcpy(c,recv->buffer,1); //décalage des len-1 octets au début du recvbuf memmove(recv->buffer,recv->buffer+1,recv->len-1); recv->len--; ptr=realloc(recv->buffer,recv->len);
C'est le moment de procéder à quelques optimisations :
memcpy(c,recv->buffer,1); Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce sera plus rapide qu'un appel à memcpy (pour un seul octet !). Ensuite ça laisse le compilateur optimiser comme il le sent (penser aux super optimisations qu'il peut faire, SSE, pipelines...) alors que le copilo peut pas beaucoup optimiser un appel de fonction (il ne sait pas trop ce qu'elle fait).
memmove et realloc Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent pas comme un octet.
Buffer vide, $==# $#***** ("") On ajoute un A $A#**** ("A") On ajoute un B $AB#*** ("AB") On lit un caractère (ici A) *$B#*** ("B") On ajoute C, D et E *$BCDE# ("BCDE") On lit deux caractères (ici B puis C) ***$DE# ("DE") On ajoute un F (attention on est au bout, le marqueur fin revient au début) F#**$DE ("DEF") Et on ajoute un G FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
La séquence suivante n'est pas très bonne. Par caractère que tu reçois tu
vas faire un appel à memcpy, memmove et realloc... c'est bon pour faire
des tests mais en production on vire tout ça.
//copie d'un octet de recvbuf dans 'c'
memcpy(c,recv->buffer,1);
//décalage des len-1 octets au début du recvbuf
memmove(recv->buffer,recv->buffer+1,recv->len-1);
recv->len--;
ptr=realloc(recv->buffer,recv->len);
C'est le moment de procéder à quelques optimisations :
memcpy(c,recv->buffer,1);
Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce
sera plus rapide qu'un appel à memcpy (pour un seul octet !). Ensuite ça
laisse le compilateur optimiser comme il le sent (penser aux super
optimisations qu'il peut faire, SSE, pipelines...) alors que le copilo
peut pas beaucoup optimiser un appel de fonction (il ne sait pas trop ce
qu'elle fait).
memmove et realloc
Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First
Out). Une méthode courament utilisée et qui évite les déplacements
mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre
la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le
buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent
pas comme un octet.
Buffer vide, $==#
$#***** ("")
On ajoute un A
$A#**** ("A")
On ajoute un B
$AB#*** ("AB")
On lit un caractère (ici A)
*$B#*** ("B")
On ajoute C, D et E
*$BCDE# ("BCDE")
On lit deux caractères (ici B puis C)
***$DE# ("DE")
On ajoute un F (attention on est au bout, le marqueur fin revient au
début)
F#**$DE ("DEF")
Et on ajoute un G
FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer
devient trop petit (fin ratrappe début)
D'autre part, je ne vois pas de fonction pour ajouter en masse des
données (comment tu le remplis ton buffer ? Octet par octet ? En réponse
à send ? beurk !)
La séquence suivante n'est pas très bonne. Par caractère que tu reçois tu vas faire un appel à memcpy, memmove et realloc... c'est bon pour faire des tests mais en production on vire tout ça.
//copie d'un octet de recvbuf dans 'c' memcpy(c,recv->buffer,1); //décalage des len-1 octets au début du recvbuf memmove(recv->buffer,recv->buffer+1,recv->len-1); recv->len--; ptr=realloc(recv->buffer,recv->len);
C'est le moment de procéder à quelques optimisations :
memcpy(c,recv->buffer,1); Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce sera plus rapide qu'un appel à memcpy (pour un seul octet !). Ensuite ça laisse le compilateur optimiser comme il le sent (penser aux super optimisations qu'il peut faire, SSE, pipelines...) alors que le copilo peut pas beaucoup optimiser un appel de fonction (il ne sait pas trop ce qu'elle fait).
memmove et realloc Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent pas comme un octet.
Buffer vide, $==# $#***** ("") On ajoute un A $A#**** ("A") On ajoute un B $AB#*** ("AB") On lit un caractère (ici A) *$B#*** ("B") On ajoute C, D et E *$BCDE# ("BCDE") On lit deux caractères (ici B puis C) ***$DE# ("DE") On ajoute un F (attention on est au bout, le marqueur fin revient au début) F#**$DE ("DEF") Et on ajoute un G FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
> le code est a : http://nicolas.aunai.free.fr/async/
case FD_READ : ioctlsocket(my_sock,FIONREAD,&recvbuf->len); recvbuf=malloc(recvbuf->len); recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est une solution mais sache qu'il est possible de le rendre persistant.
> le code est a : http://nicolas.aunai.free.fr/async/
case FD_READ :
ioctlsocket(my_sock,FIONREAD,&recvbuf->len);
recvbuf=malloc(recvbuf->len);
recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à
recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en
envoie que n<m.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est
une solution mais sache qu'il est possible de le rendre persistant.
> le code est a : http://nicolas.aunai.free.fr/async/
case FD_READ : ioctlsocket(my_sock,FIONREAD,&recvbuf->len); recvbuf=malloc(recvbuf->len); recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est une solution mais sache qu'il est possible de le rendre persistant.
case FD_READ : ioctlsocket(my_sock,FIONREAD,&recvbuf->len); recvbuf=malloc(recvbuf->len); recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre inférieure a la taille présente sur la socket, cependant tu m'a dit toi même que si tel était le cas en pratique, j'aurai un autre FD_READ pour m'annoncer les m-n octets restant. ceux ci seront (tous ou pas) reçu dans le recvbuf et traités.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est une solution mais sache qu'il est possible de le rendre persistant.
le recvbuf n'est qu'un intermédiare entre la socket et les buffers de stockage du header et du body. il est lu par les fonctions recv_header et recv_body, et a la fin de reception() il est vidé, et sa taille est nulle.
il sera réalloué (alloué tout court en fait car libéré avant.) lors d'un autre FD_READ.
case FD_READ :
ioctlsocket(my_sock,FIONREAD,&recvbuf->len);
recvbuf=malloc(recvbuf->len);
recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à
recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en
envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre
inférieure a la taille présente sur la socket, cependant tu m'a dit toi
même que si tel était le cas en pratique, j'aurai un autre FD_READ pour
m'annoncer les m-n octets restant. ceux ci seront (tous ou pas) reçu
dans le recvbuf et traités.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est
une solution mais sache qu'il est possible de le rendre persistant.
le recvbuf n'est qu'un intermédiare entre la socket et les buffers de
stockage du header et du body. il est lu par les fonctions recv_header
et recv_body, et a la fin de reception() il est vidé, et sa taille est
nulle.
il sera réalloué (alloué tout court en fait car libéré avant.) lors
d'un autre FD_READ.
case FD_READ : ioctlsocket(my_sock,FIONREAD,&recvbuf->len); recvbuf=malloc(recvbuf->len); recv(my_sock,recvbuf->buffer,recvbuf->len,0);//on reçoit les données
Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre inférieure a la taille présente sur la socket, cependant tu m'a dit toi même que si tel était le cas en pratique, j'aurai un autre FD_READ pour m'annoncer les m-n octets restant. ceux ci seront (tous ou pas) reçu dans le recvbuf et traités.
Reception(network,recvbuf);
Si j'ai bien compris, à la fin de cette fonction recvbuf est nul ? C'est une solution mais sache qu'il est possible de le rendre persistant.
le recvbuf n'est qu'un intermédiare entre la socket et les buffers de stockage du header et du body. il est lu par les fonctions recv_header et recv_body, et a la fin de reception() il est vidé, et sa taille est nulle.
il sera réalloué (alloué tout court en fait car libéré avant.) lors d'un autre FD_READ.
memcpy(c,recv->buffer,1); Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce sera plus rapide qu'un appel à memcpy (pour un seul octet !).
oui ça j'allais le faire.
memmove et realloc Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent pas comme un octet.
Buffer vide, $==# $#***** ("") On ajoute un A $A#**** ("A") On ajoute un B $AB#*** ("AB") On lit un caractère (ici A) *$B#*** ("B") On ajoute C, D et E *$BCDE# ("BCDE") On lit deux caractères (ici B puis C) ***$DE# ("DE") On ajoute un F (attention on est au bout, le marqueur fin revient au début) F#**$DE ("DEF") Et on ajoute un G FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de recpetion de mon programme où se situerai ce buffer ? entre recvbuf et les headbuf et bodybuf ?
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le recvbuf et les buffers de stockage du header et du body.
memcpy(c,recv->buffer,1);
Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce
sera plus rapide qu'un appel à memcpy (pour un seul octet !).
oui ça j'allais le faire.
memmove et realloc
Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First
Out). Une méthode courament utilisée et qui évite les déplacements
mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre
la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le
buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent
pas comme un octet.
Buffer vide, $==#
$#***** ("")
On ajoute un A
$A#**** ("A")
On ajoute un B
$AB#*** ("AB")
On lit un caractère (ici A)
*$B#*** ("B")
On ajoute C, D et E
*$BCDE# ("BCDE")
On lit deux caractères (ici B puis C)
***$DE# ("DE")
On ajoute un F (attention on est au bout, le marqueur fin revient au
début)
F#**$DE ("DEF")
Et on ajoute un G
FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer
devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de
recpetion de mon programme où se situerai ce buffer ? entre recvbuf et
les headbuf et bodybuf ?
D'autre part, je ne vois pas de fonction pour ajouter en masse des
données (comment tu le remplis ton buffer ? Octet par octet ? En réponse
à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le
recvbuf et les buffers de stockage du header et du body.
memcpy(c,recv->buffer,1); Non. Il *faut* que tu mettes "*c = *(char*)recv->buffer". D'une part ce sera plus rapide qu'un appel à memcpy (pour un seul octet !).
oui ça j'allais le faire.
memmove et realloc Là tu peux t'épargner quelques appels à ces fonctions :
Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Voilà en gros comment ça marche. "$" marque le début et "#" la fin. le buffer contient les lettre de l'alphabet. Evidemment $ et # ne comptent pas comme un octet.
Buffer vide, $==# $#***** ("") On ajoute un A $A#**** ("A") On ajoute un B $AB#*** ("AB") On lit un caractère (ici A) *$B#*** ("B") On ajoute C, D et E *$BCDE# ("BCDE") On lit deux caractères (ici B puis C) ***$DE# ("DE") On ajoute un F (attention on est au bout, le marqueur fin revient au début) F#**$DE ("DEF") Et on ajoute un G FG#*$DE ("DEFG")
Ainsi de suite....
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de recpetion de mon programme où se situerai ce buffer ? entre recvbuf et les headbuf et bodybuf ?
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le recvbuf et les buffers de stockage du header et du body.
>> Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre inférieure a la taille présente sur la socket, cependant tu m'a dit toi même que si tel était le cas en pratique, j'aurai un autre FD_READ pour m'annoncer les m-n octets restant. ceux ci seront (tous ou pas) reçu dans le recvbuf et traités.
Ouaip, mais tant qu'à faire autant tout lire d'un coup, ça évitera de traiter plusieurs messages.
>> Le mieux serait que tu boucles sur recv tant qu'il y a des choses à
recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send
t'en envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre
inférieure a la taille présente sur la socket, cependant tu m'a dit
toi même que si tel était le cas en pratique, j'aurai un autre FD_READ
pour m'annoncer les m-n octets restant. ceux ci seront (tous ou pas)
reçu dans le recvbuf et traités.
Ouaip, mais tant qu'à faire autant tout lire d'un coup, ça évitera de
traiter plusieurs messages.
>> Le mieux serait que tu boucles sur recv tant qu'il y a des choses à recevoir. Il se peut qu'il y ait m octets sur la pile tcp et que send t'en envoie que n<m.
je sais bien que la longueur annoncée par ioctolsocket peut etre inférieure a la taille présente sur la socket, cependant tu m'a dit toi même que si tel était le cas en pratique, j'aurai un autre FD_READ pour m'annoncer les m-n octets restant. ceux ci seront (tous ou pas) reçu dans le recvbuf et traités.
Ouaip, mais tant qu'à faire autant tout lire d'un coup, ça évitera de traiter plusieurs messages.
>> Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de recpetion de mon programme où se situerai ce buffer ? entre recvbuf et les headbuf et bodybuf ?
A la place de recvbuf.
Ma remarque est que implémenté comme-ça ton code de gestion de buffer n'est pas performant du tout.
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le recvbuf et les buffers de stockage du header et du body.
Une bonne implémentation de buffer fournit ce type de fonction. C'est une mauvaise idée de faire comme tu fais, à savoir mettre le code de construction de buffer (ici en réponse à un FD_READ) et celui d'utilisation à deux endroits différents.
>> Ce que tu cherches à faire c'est en fait une pile FIFO (First In
First Out). Une méthode courament utilisée et qui évite les
déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le
début et l'autre la fin d'un buffer "cyclique".
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton
buffer devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de
recpetion de mon programme où se situerai ce buffer ? entre recvbuf et
les headbuf et bodybuf ?
A la place de recvbuf.
Ma remarque est que implémenté comme-ça ton code de gestion de buffer
n'est pas performant du tout.
D'autre part, je ne vois pas de fonction pour ajouter en masse des
données (comment tu le remplis ton buffer ? Octet par octet ? En
réponse à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le
recvbuf et les buffers de stockage du header et du body.
Une bonne implémentation de buffer fournit ce type de fonction. C'est une
mauvaise idée de faire comme tu fais, à savoir mettre le code de
construction de buffer (ici en réponse à un FD_READ) et celui
d'utilisation à deux endroits différents.
>> Ce que tu cherches à faire c'est en fait une pile FIFO (First In First Out). Une méthode courament utilisée et qui évite les déplacements mémoire est d'utiliser deux pointeurs, l'un marquant le début et l'autre la fin d'un buffer "cyclique".
Donc tu n'as à réallouer/déplacer de la mémoire que lorsque ton buffer devient trop petit (fin ratrappe début)
hum je vois pas trop l'utilité pour le moment. dans la chaine de recpetion de mon programme où se situerai ce buffer ? entre recvbuf et les headbuf et bodybuf ?
A la place de recvbuf.
Ma remarque est que implémenté comme-ça ton code de gestion de buffer n'est pas performant du tout.
D'autre part, je ne vois pas de fonction pour ajouter en masse des données (comment tu le remplis ton buffer ? Octet par octet ? En réponse à send ? beurk !)
mes fonctions buffer_get/put_char ne sont utilisée uniquement entre le recvbuf et les buffers de stockage du header et du body.
Une bonne implémentation de buffer fournit ce type de fonction. C'est une mauvaise idée de faire comme tu fais, à savoir mettre le code de construction de buffer (ici en réponse à un FD_READ) et celui d'utilisation à deux endroits différents.