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

Windows Discussion :

serveur avec un pipe nommé en overlapped : comment utiliser getOverlappedResult() avec ReadFile() ?


Sujet :

Windows

  1. #1
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Points : 177
    Points
    177
    Par défaut serveur avec un pipe nommé en overlapped : comment utiliser getOverlappedResult() avec ReadFile() ?
    Je me suis plongé à nouveau dans la doc de MSDN pour écrire ce client/serveur en overlapped, et je bute toujours. Je décris un peu le programme :

    J'ai 2 threads:

    1) le thread principal qui ouvre un pipe nommé en overlapped, puis qui boucle sur WaitForMultipleObjects(). Celle-ci attends 3 events manuels. Le premier est l'event qui permet de savoir si un client se connecte, le second permet de sortir de l'application, et le troisième devrait gérer les données arrivant dans le pipe (il est utilisé par ReadFile())

    2) le deuxième thread n'est appelé que si le client se connecte. Il boucle sur ReadFile().

    voici le code:

    http://pastebin.com/5rka7dK7

    Il y a principalement 4 fonctions (je ne compte pas la fonction qui affiche les erreurs):

    a) svr_new: elle crée le pipe en overlapped et les events et appelle ConnectNamedPipe()

    b) svr_del qui libère les ressources

    c) _read_data_cb: le thread qui appelle ReadFile()

    d) la fonction main, le thread principal, qui boucle sur WaitForMultipleObjects()

    D'après la doc MSDN, vu que j'ouvre le pipe en overlapped, je dois passer une autre structure OVERLAPPED (dans le code, c'est svr->ol_read).

    Maintenant, voici ce que je n'ai pas compris:

    • est-ce que je dois appeler GetOverlappedResult() ?
    • si oui, où ? Dès que le résultat de GetLastError() de ReadFile() renvoie ERROR_IO_PENDING (ligne 50 du paste) ? Quand WaitForMultipleObjects() retourne (ligne 303 du paste, je l'ai commenté) ? Ailleurs ?
    • Je fais un ResetEvent() de l'event de Readfile() quand WaitForMultipleObjects() retourne (ligne 302 du paste). C'est au bon endroit ?


    Avec le code que j'ai pasté, voici le résultat (le buffer de ReadFile() est de 5 octets) si le client envoie les 24 octets suivants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    salut, c'est le client !
    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
    $ ./server.exe
    waiting for client...
    WaitForMultipleObjects : 0
    client connected (1)
    WaitForMultipleObjects : 2
     * ReadFile : 5
    WaitForMultipleObjects : 2
     * ReadFile : 5
    WaitForMultipleObjects : 2
     * ReadFile : 5
    WaitForMultipleObjects : 2
     * ReadFile : 5
    WaitForMultipleObjects : 2
     * ReadFile : 4
    Remarque: WaitForMultipleObjects() peut être appelé moins que ça. Ca a l'air aléatoire.

    Donc getOverlappedResult() n'est pas appelé, ReadFile() réussit comme il faut (il lit 5*4 + 4 = 24 octets), mais je ne sais pas quand l'opération se termine.

    Si je mets un printf() quand ReadFile() échoue avec ERROR_IO_PENDING, ce printf() est appelé indéfiniment.

    De plus, le client envoie 2 messages. Celui ci-dessus, et un autre 2 secondes après. Le 2ème n'est jamais lu et ReadFile() "échoue" avec une erreur autre que ERROR_IO_PENDING ou ERROR_BROKEN_PIPE: ERROR_SUCCESS... (ReadFile() renvoie 0 et GetLastError() renvoie ERROR_SUCCESS)

    Bref, je suis perdu. J'ai cherché des heures sur Internet, j'ai regardé les codes d'exemples de MSDN, du SDK, etc... Je ne pige toujours rien à ce que je dois faire dans mon cas particuliers.

    Quelqu'un peut m'expliquer comment utiliser GetOverlappedResult() si on doit l'utiliser (et où l'utiliser), voire corriger mon code ?

    Merci
    L'Opus attire les Prélats

  2. #2
    Membre habitué
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    81
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 81
    Points : 128
    Points
    128
    Par défaut
    Si l'évènement de lecture asynchrone associé est le troisième de ton tableau d'évènements :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    objects[2] = svr->ol_read.hEvent;
    Il faut tester le troisième (tu étais bien parti) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if (ret == (WAIT_OBJECT_0 + 2))
    {
            ResetEvent(svr->ol_read.hEvent);
    
            /* Ici, il faut faire le GetOverlappedResult pour récupérer les données lues de manière asynchrone */
            ...
    
            /* Là, il faut relancer une demande de lecture asynchrone donc faire un nouveau ReadFile */
            ...
    }
    Et préalablement à la boucle d'attente (WaitForMultipleObjects), il faut faire un premier ReadFile pour demander une première lecture.

  3. #3
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Points : 177
    Points
    177
    Par défaut
    Je n'attendais plus de réponses, au point que j'ai continué à chercher sur le net, et j'ai changé mon fusil d'épaule. Apparemment, pour ce que je veux faire, les I/O completion port sont meilleurs (en plus, les fonctions *WAITForMultipleObjects ont un max de 64 objets sur lesquels elles attendent, ce qui est peu).

    Donc, voilà les codes du serveur et du client.

    Le problème est dans le serveur (j'améliorerai le client quand le serveur sera nickel)

    J'utilise les I/O completion port comme ceci : en gros, je lance un thread qui appelle ReadFile() dès que le client se connecte. Si ReadFile() retourne TRUE, je chope toutes les données avec des appels successifs à ReadFile(). Si Readfile() retourne FALSE et si l'erreur est ERROR_IO_PENDING,, j'attends avec GetQueuedCompletionStatus().

    Ce qui me semble bizarre est que si le premier appel à ReadFile() renvoie TRUE, dans la boucle qui fait les appels suivants à ReadFile(), le dernier ReadFile() echoue avec l'erreur RROR_IO_PENDING

    Exemple: le thread qui appelle ReadFile() commence ligne 64 du code du serveur. Le client envoie 24 octets ("salut, c'est le client !") et le buffer du ReadFile() du serveur est de 5 octets (pour tester le cas où le buffer du ReadFile() est plus petit que les données envoyées par le client).

    Dans le terminal, j'ai:

    waiting for client...
    WaitForMultipleObjects : 0
    client connected (1)
    ReadFile 1 msg (5 -> 05) : salut
    ReadFile 2 msg (5 -> 10) : salut, c'e
    ReadFile 2 msg (5 -> 15) : salut, c'est le
    ReadFile 2 msg (5 -> 20) : salut, c'est le clie
    ReadFile 2 msg (4 -> 24) : salut, c'est le client !
    ReadFile2: ERROR_IO_PENDING
    GQCIOS 0 255 003D3A18
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING
    GQCIOS 5 255 003D3A2C
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING
    GQCIOS 5 255 003D3A2C
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING
    GQCIOS 5 255 003D3A2C
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING
    GQCIOS 5 255 003D3A2C
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING
    GQCIOS 4 255 003D3A2C
    ReadFile3: ERROR_IO_PENDING
    ReadFile1: ERROR_IO_PENDING

    Ce que je ne comprends pas est que, même si je lis toutes les données (ReadFile 2 msg (4 -> 24) : salut, c'est le client !), ReadFile() renvoie un opération en attente ("ReadFile2: ERROR_IO_PENDING")

    Donc, est-ce que j'utilise mal ReadFile() et GetQueuedCompletionStatus() ? Est-ce que ma boucle est mal conçue ?

    merci
    L'Opus attire les Prélats

  4. #4
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    340
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 340
    Points : 177
    Points
    177
    Par défaut
    bon, en fait, on ne peut pas utiliser Wait* et les I/O completion port en même temps. Donc, pas de I/O completion port pour moi (même si c'est plus puissant et si ça permet de s'affranchir des 64 objets max qu'on peut utiliser avec WaitForMultipleObjects, c'est une horreur à utiliser correctement)
    L'Opus attire les Prélats

Discussions similaires

  1. [VBA] Comment utiliser Access avec Excel
    Par MxPx_23 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 09/02/2006, 12h00
  2. Comment utiliser Word avec Delphi 7 ?
    Par muquet dans le forum Débuter
    Réponses: 9
    Dernier message: 06/12/2005, 18h52
  3. Comment utiliser ShellExecute avec un programme DOS ?
    Par RC10GT_MGT dans le forum API, COM et SDKs
    Réponses: 9
    Dernier message: 22/09/2005, 14h23
  4. Comment utiliser AddItem avec un TComboBox ?
    Par richard038 dans le forum Composants VCL
    Réponses: 7
    Dernier message: 01/08/2005, 17h58
  5. Réponses: 12
    Dernier message: 02/02/2004, 13h41

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