2013-04-01 8 views
3

J'ai du code qui exécute des requêtes HTTP en utilisant les API WinInet de manière asynchrone. En général, mon code fonctionne, mais je suis confus au sujet de la «bonne» façon de faire les choses. Dans la documentation InternetReadFile(), il déclare:Manière correcte d'utiliser InternetReadFile() de manière asynchrone

Pour que toutes les données sont extraites, une application doit continuer à appeler la fonction InternetReadFile jusqu'à ce que la fonction retourne TRUE et le paramètre lpdwNumberOfBytesRead est égal à zéro.

mais en mode asynchrone, il peut (ou non) return false, et une erreur de ERROR_IO_PENDING, indiquant qu'il fera le travail de manière asynchrone, et appeler mon rappel lorsque vous avez terminé. Si je lis littéralement la documentation, il semble que les appels asynchrones pourraient également faire une lecture partielle du tampon demandé, et exiger que l'appelant continue d'appeler InternetReadFile jusqu'à ce qu'une lecture de 0 octet soit rencontrée.

Une implémentation typique utilisant InternetReadFile() serait synchroniquement ressembler à quelque chose comme ceci:

while(InternetReadFile(Request, Buffer, BufferSize, &BytesRead) && BytesRead != 0) 
{ 
    // do something with Buffer 
} 

mais avec la possibilité que tout un appel à InternetReadFile() pourrait signaler qu'il va faire le travail de manière asynchrone (et peut-être lire une partie, mais pas tout de votre demande), il devient beaucoup plus compliqué. Si je passe à MSDN sample code pour des conseils, l'implémentation est simple, appelant simplement InternetReadFile() une fois, et attend un seul retour ayant lu la totalité du tampon demandé soit instantanément soit asynchrone. Est-ce la façon correcte d'utiliser cette fonction, ou MSDN Sample Code ignore-t-il la possibilité que InternetReadFile() lira seulement une partie de la mémoire tampon demandée?

Répondre

3

Après une lecture plus attentive de l'exemple asynchrone, je vois maintenant qu'il lit à plusieurs reprises jusqu'à ce qu'une lecture réussie de 0 octets soit rencontrée. Donc, pour répondre à ma propre question, vous devez appeler InternetReadFile() encore et encore, et être prêt pour une réponse synchrone ou asynchrone.

3

Lecture InternetReadFile() répétée jusqu'à ce qu'elle renvoie TRUE et BytesRead est 0 est une façon correcte d'utiliser InternetReadFile(), mais pas assez si vous travaillez de manière asynchrone.

Comme MSDN dit

Lors de l'exécution de manière asynchrone, si un appel à InternetReadFile ne donne pas lieu à une transaction terminée, elle retourne FALSE et un appel ultérieur à GetLastError retournera ERROR_IO_PENDING. Lorsque la transaction est terminée, InternetStatusCallback spécifié dans un précédent appel à InternetSetStatusCallback sera appelé avec INTERNET_STATUS_REQUEST_COMPLETE.

Alors InternetReadFile() peut revenir FALSE et mettre la dernière erreur de ERROR_IO_PENDING valeur si vous travaillez en mode asynchrone.

Quand InternetSetStatusCallback sera appelé à nouveau avec INTERNET_STATUS_REQUEST_COMPLETE, le paramètre lpvStatusInformation contiendra l'adresse d'une structure INTERNET_ASYNC_RESULT (voir InternetStatusCallback callback function). Le membre INTERNET_ASYNC_RESULT.dwResult contiendra le résultat d'une opération asynchrone (ou TRUEFALSE depuis que vous avez appelé InternetReadFile) et le INTERNET_ASYNC_RESULT.dwError contiendra un code d'erreur que si dwResult est FALSE.

Si dwResult est TRUE alors votre Buffer contient des données lues sur Internet, et le BytesRead contient le nombre d'octets lus de manière asynchrone.

Donc l'une des choses les plus importantes lorsque vous travaillez de manière asynchrone, le Buffer et la BytesReaddoit être persistant entre InternetStatusCallback appels, à savoir ne doit pas être alloué sur la pile. Sinon, il a un comportement indéfini, provoque une corruption de la mémoire, etc.

Questions connexes