zoukankan      html  css  js  c++  java
  • Windows Mobile下WinInet的异步使用方法

    codeproject上有一篇老美写的关于HTTP异步的文章:http://www.codeproject.com/KB/IP/asyncwininet.aspx

    我做HTTP异步的时候,也是参考了这篇文章,受益匪浅。今天特地翻译出来,与大家共飨。

    WinInet HTTP的异步方式使用

    绪论

    如果你曾经深入MSDN研究过WinInet API,你会注意到可使用异步方式且该方式是被推崇的。

    当你决定使用该方式时,你却找不到如何使用异步的说明。网上也没有任何例子。研究了很长时间,也做了很多试验,我最终决定着手来填补一份(非官方)空缺的文档。

    为什么异步方式是最好的?因为它能够正确的处理超时。而在IE5.5下WinInet缺少此功能。

    如果你试图使用TerminateThreadCloseHandle函数来处理超时(这些函数在MSDN文档中有介绍),你将落入各种各样的陷阱中。

    以下条件中异步测试成功:单处理器和多处理器的WinNT4系统下的IE4.01SP3, IE5.0, IE5.01, IE5.5SP1,压力环境(12小时不间断地在多处理器NT服务器下运行15个并发实例)。

    原理
    使用WinInet函数的异步方式,你必须按照正确的顺序:
    1.使用INTERNET_FLAG_ASYNC打开任务。
    2.使用InternetSetStatusCallback设置回调。
    3.使用InternetOpenUrl打开连接。
    4.如果InternetOpenUrl返回NULLGetLastError的值是ERROR_IO_PENDING
      1)等待回调函数返回INTERNET_STATUS_HANDLE_CREATED通知,保存连接句柄;
      2)等待回调函数返回INTERNET_STATUS_REQUEST_COMPLETE通知。
    5.解析header里的vontent-length字段,创建一个INTERNET_BUFFERS结构:
      1)dwStructSize = sizeof(INTERNET_BUFFERS);
      2)lpvBuffer = 你申请的缓冲;
      3)dwBufferLength = 缓冲长度。
    6.使用InternetReadFileEx函数,参数为IRF_ASYNC,异步读取剩余的数据。不要使用InternetReadFile,因为它是同
    步的。
    7.如果InternetReadFileEx返回FALSEGetLastError的值为ERROR_IO_PENDING:等待回到函数返回INTERNET_STATUS_
    REQUEST_COMPLETE 通知。
      警告:INTERNET_BUFFERS结果的成员是会被修改的(dwBufferLength和缓冲区)
    8.如果dwBufferLength不为0,移动lpvBuffer的指针dwBufferLength个长度,重复第6步。
    9.使用InternetCloseHandle关闭连接,等待INTERNET_STATUS_HANDLE_CLOSING和特定的INTERNET_STATUS_REQUEST_CO
    MPLETE通知。

    之后,你可以开始一个新的连接过程或者关闭任务句柄。但是在关闭之前,你应该卸载回调函数。

    细节
    在原理中,让我们看看关键点的一些代码:

    1&2:使用INTERNET_FLAG_ASYNC打开任务,设置回调
    m_Session = InternetOpen(AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG,
                              NULL, NULL, INTERNET_FLAG_ASYNC);
    InternetSetStatusCallback( m_Session,
          (INTERNET_STATUS_CALLBACK)InternetCallbackFunc );

    3&4:使用InternetOpenUrl打开连接,等待INTERNET_STATUS_REQUEST_COMPLETE通知
    使用lParam发送一个任务表示到你的回调。我总是用this指针来传递我的class。这里假设你知道如何处理回调。
    InternetOpenUrl( m_Session, uurl, NULL, 0,
          INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE |
          INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)this );

    回调会收到一堆的消息。这是收到的dwInternetStatus值的顺序:
    [openUrl] InternetStatus: 60 INTERNET_STATUS_HANDLE_CREATED
    **此时你应该保存HINTERNET句柄,如下代码:
    INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
    m_hHttpFile = (HINTERNET)(res->dwResult);

    [openUrl] InternetStatus: 10
    [openUrl] InternetStatus: 11
    [openUrl] InternetStatus: 20
    [openUrl] InternetStatus: 21
    [openUrl] InternetStatus: 30
    [openUrl] InternetStatus: 31
    [openUrl] InternetStatus: 40
    [openUrl] InternetStatus: 41
    [openUrl] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

    5:解析content-length,创建INTERNET_BUFFERS结构
    一旦你得到了句柄,调用HttpQueryInfo(使用HTTP_QUERY_CONTENT_LENGTH标记)得到接收数据的大小。如果HTTP头里
    没有content-length参数,函数会失败。
    创建INTERNET_BUFFERS结构。
    INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
    ib.lpvBuffer = 你申请的缓冲
    ib.dwBufferLength = 缓冲长度
    dwBufferTotal供你自己使用,永远不会被WinInet该变(据我所知)。我用它来存储收到数据的总长度。

    6&7&8:循环读取剩余数据
    调用InternetReadFileEx(使用IRF_ASYNC标记)异步读取剩余数据。不要使用InternetReadFile,因为它是同步函数。

    你必须循环调用InternetReadFileEx,直到ib.dwBufferLength为0。在每次循环前你必须调整lpvBuffer指针位置,重置ib.dwBufferLength。
    BOOL bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
    if(!bOk && GetLastError()==ERROR_IO_PENDING)
      等待...

    while( bOk && ib.dwBufferLength!=0 )
    {
      (调整ib值)
      bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
      if(!bOk && GetLastError()==ERROR_IO_PENDING)
        等待...
    }

    你的回调函数会收到这些消息:
    [connect] InternetStatus: 40 (receiving response)
    [connect] InternetStatus: 41 (response received)
    [connect] InternetStatus: 50
    [connect] InternetStatus: 51
    还可能
    [connect] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

    最后一个只有在GetLastError值为ERROR_IO_PENDING才会得到。如果你用dwBufferTotal存储了数据总大小(按字节),把你的字符缓冲最后一位置置为0(如果是字符的话)。
    buf[ib.dwBufferTotal] = 0;

    9:关闭连接句柄
    InternetCloseHandle( m_httpFile );
    关闭时,回调会收到这个消息:
    [connect] InternetStatus: 70 INTERNET_STATUS_HANDLE_CLOSING

    大多数错误例子中,连接都会出乎意料的关闭。此时,你会收到70在100(INTERNET_STATUS_REQUEST_COMPLETE)之后。

    此情形在整个过程都可能会发生。

    10:关闭m_Session句柄前
    你应该卸载回调:
    InternetSetStatusCallback( m_Session, NULL );

    以上将帮助那些使用WinInet异步方式的人。(之后是老美希望大家购买他的代码,略过...)

  • 相关阅读:
    CodeForces 219D Choosing Capital for Treeland (树形DP)
    POJ 3162 Walking Race (树的直径,单调队列)
    POJ 2152 Fire (树形DP,经典)
    POJ 1741 Tree (树的分治,树的重心)
    POJ 1655 Balancing Act (树的重心,常规)
    HDU 2196 Computer (树形DP)
    HDU 1520 Anniversary party (树形DP,入门)
    寒门子弟
    JQuery选择器(转)
    (四)Web应用开发---系统架构图
  • 原文地址:https://www.cnblogs.com/fengju/p/6173561.html
Copyright © 2011-2022 走看看