Miniserveur HTML multithread : faire un SEND bloquant ? [Résolu]

Signaler
Messages postés
149
Date d'inscription
jeudi 22 avril 2004
Statut
Membre
Dernière intervention
10 décembre 2009
-
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007
-
Bonjour

J'essaye de réaliser un serveur HTML multithread dans le cadre d'un projet :
j'utilise des sockets de type SOCK_STREAM.

Afin de ne pas fermer la connexion avec le client avant d'avoir effectué la totalité de l'envoi de la page demandée (ou du fichier binaire : image, activex etc...) j'ai écrit une routine qui saucissone le buffer en blocs de 1024 octets maxi...

En local sur ma machine ça fonctionne assez bien.
Mais pour l'accès à partir d'une autre machine (réseau local) j'ai du introduire un délai de 15 ms entre chaque envoi de bloc sinon la connexion est coupée avant la fin de l'envoi.

En accès distant je crains de devoir indiquer une valeur encore plus grande.
Tout ça ne me semble pas trés propre.

Problèmes rencontrés :
-Si le délai entre deux envois de blocs est trop court les fichiers envoyés sont tronqués (image incomplètes, etc.)
-Si le client fait un refresh trop tôt (trop grand nombre de requetes) le serveur renvoit n'importe quoi et le navigateur affiche des caractères incompréhensibles.

A l'évidence dans un cas comme dans l'autre il y a bien perte d'intégrité des données transmises...

Bien sûr je pourrais mettre un Sleep de folie mais ça me paraît innacceptable comme solution !

Quelqu'un connait un moyen de savoir, lors d'un SEND si le client a reçu la totalité des données envoyées avant de fermer la connexion ?

Merci

"(...)
    lgenvoi = 10;
    erreurs = 0;
    do
        {
            Sleep (15);                        //ajustement "empirique"    15ms
                lg = 1024; //SO_MAX_MSG_SIZE;      //ajustement "empirique"    1024
                lg = min (lg, lgtotal-lgenvoi);
                cr = send(laSocket[NoThread], &buffer[lgenvoi], lg, 0);
                if (cr<0)
                {
                       Sleep (0);
                       erreurs++;
                       if erreurs> 5)
                       {
                          cr=WSAGetLastError ();
                          break;
                }
                       else
                         continue;
            }
            lgdata += cr;
                Sleep (0);
         } while (lgenvoi < lgtotal);

(...)

    closesocket (laSocket[NoThread]);
       SocketsEntrant[NoThread] = INVALID_SOCKET;
    AdresseIpClient[NoThread] = "";

(...)
"

7 réponses

Messages postés
149
Date d'inscription
jeudi 22 avril 2004
Statut
Membre
Dernière intervention
10 décembre 2009

Salut The_Guardian

Comme tu le présentais j'avais qques soucis avec mes sémaphores .

J'avais aussi des erreurs WSAWOULDBLOCK dans ma boucle alors que ma socket était non bloquante

Je suis tombé sur un site qui m'a bien aidé sur le coup.

http://tangentsoft.net/wskfaq/

J'y ai appris beaoucoup de choses, entre autres comment fermer plus proprement une socket en utilisant
shutdown et en attendant le compte-rendu 0 avant de faire le closesocket...

En fait j'y ai appris que l'erreur WSAWOULDBLOCK était une occurence normale quand on travaillait avec des sockets non bloquants. Elle veut simplement dire que le système ne peut plus "bufferiser" de nouvelles données à envoyer. Il suffit d'attendre...

Dans ma boucle je compte donc toutes les erreurs avec un sous-total pour l'erreur WSAWOULDBLOCK et pour sortir de la boucle je teste

"if (nberr-nberrWouldBlock > 5 || cr==INVALIDE_SOCKET)"

et ça marche pas trop mal.

Merci pour ton aide
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

Bonjour,

Ton problème est étonnant
_  tu ne dois surtout pas faire de sleep pour garantir l'intégrité des données. TCP se charge de ça pour toi. Commence donc par enlever tes sleep alors.
- réflechissons ensemble
1) pourquoi ton client reçoit n'importe quoi quand les envois sont trop proches ?
- deux possibilités
(a) ton client est mauvais (ce dont je doute, vu que tu dois utiliser je suppose un browser habituel)
(b) c'est ton émission qui est mauvaise
- quand tu fais ton send( ), le buffer est copié dans un endroit propre,  donc tu as pas de risque d'écrasement du buffer
- à moins que... à moins que tu fasses de la lecture dans un thread d'émission et de l'écriture dans le buffer, à partir d'un thread différent. Et ça ça pourrait te poser des problèmes
Et il y a un autre problème aussi, celui des refreshs
- quand tu fais un refresh, le client coupe la connexion et en ouvre une autre , ton serveur peut détecter la coupure de la connexion parce que le send va renvoyer des valeurs d'erreur notamment, et dans ce cas là, il peut fermer la connexion

Bon maintenant que tu aies trop de requêtes c'est étrange..

Question : pourrais-tu donner un exemple plus concret de ce qui se passe quand tu rafraichis ?

Et pour ta dernière question:
_ pour savoir si un client a bien reçu toutes les données
- soit tu ne t'en préoccupes pas (TCP gère ça pour toi)
- soit tu demandes au client d'acquitter,  mais là tu sors du protocole HTTP..

Bon courage et pour tes prochaines questions, pense à expliquer davantage ton architecture avec les threads écrivains et les threads lecteurs. :p

=


 

Une autruche ne se cuit pas aux petits lardons
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

Re,

Et en y réflèchissant, à mon avis c'est ça ton problème: des threads partout et du coup tu contrôles  mal ce qui se passe...

=

Une autruche ne se cuit pas aux petits lardons
Messages postés
149
Date d'inscription
jeudi 22 avril 2004
Statut
Membre
Dernière intervention
10 décembre 2009

Salut The_guardian

Sans les Sleep ça marche parfaitement si le serveur et le client sont sur la même machine. Pas besoin de Sleep ou autre magouilles. Mais intérêt trés limité
Dès que je teste depuis un autre poste, en réseau local, ça part en live et les envois sont corrompus ou incomplets...Mes clients: les 2 navigateurs les plus utilisés bien sûr, IE et Firefox (pas de soucis de ce côté là, le bug est de mon côté là c'est sùr )

Il me semble que le fait de fermer la connexion immédiatement après avoir fait le dernier Send arrête l'envoi des données : si le buffer (tampon de données en attente) n'a pas eu le temps de se vider, oups ! Le close Socket fait un massacre !
Est-ce que TCP/IP "empile" l'appel au close Socket et l'exécute après seulement que le buffer soit complétement envoyé ? Il me semble que non. En plus comme tu le souligne les navigateurs n'envoyent pas d'accusé de réception (ça serait trop simple).

Quand je consulte une page html qui contient par exemple 4 images grand format, le navigateur ouvre plusieurs threads (1 pour la page et autant que nécessaire pour les liens vers des images contenus dans la page ). Si on fait un refresh mon serveur peut ne pas avoir fini d'envoyer tous ces éléments...

Si une des images demandées a été envoyée son thread est utilisable pour un nouvel envoi.

Pour les refresh : puisque le client à qui je suis, le cas échéant, en train d'envoyer des données s'est déconnecté est-ce que je ne devrais pas sortir de ma boucle d'envoi dès la première erreur constatée.

Et pour répondre à ta question sur les threads utilisés j'ai un thread d'écoute et un d'écriture effectivement, et un tableau de buffers et de flag d'envois, mais j'utilise des sémaphores pour éviter les conflits d'accès et que ça parte en sucette.
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

Re,

Ok quand tu fais ton close, les données en attente vont être envoyées, c'est pas un arrêt brutal.

_ pour les refresh, oui, tu devrais sortir de ta boucle d'envoi dès la première erreur rencontrée
_ en gros, c'est pas normal que tu aies une erreur de ce type, vérifie bien tes sémaphores, fais le contrôle d'erreur qui sort de la boucle dès qu'un client se déconnecte, puis reposte du code pour qu'on voit ça plus en détail si ça marche toujours pas.
Car c'est sencé marcher ton truc, si tu fais pleins de send et un close ben tout sera envoyé.
 erf souci mais ou?
=
Une autruche ne se cuit pas aux petits lardons
Messages postés
149
Date d'inscription
jeudi 22 avril 2004
Statut
Membre
Dernière intervention
10 décembre 2009

Ok ! Je vais tout remettre à plat suivre tes conseils, puis faire de nouveaux tests

Merci encore

A+
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

Ah c'est interressant ça de savoir, merci aussi alors :p

=
 

Une autruche ne se cuit pas aux petits lardons :p