请教各位高手一个关于异步读取HTTP的问题。程序主要结构:
用户界面主线程
循环读取HTTP网页子线程:每隔5s钟重复读取一个HTTP页面,并解析其中的数据主要操作流程:
用户点击界面按钮,调用BeginLoop函数,该函数创建一个子线程,循环读取指定的URL对应的内容。子线程函数代码如下:
UINT CHttpDownRequest::LoopThreadProc(LPVOID lpParameter)
{
UINT uRes = 0;
        //获取本类对象的唯一实例
CHttpDownRequest* pRequest = CHttpDownRequest::GetInstance();
try
{
do {
//发送请求,并获取响应数据
CMemFile* pResult = pRequest->SendEx(strUrl); if (pResult != NULL) 
{       
                                //解析返回的数据
pRequest->ParseData(pResult); delete pResult;
}

//等待线程结束事件
                        DWORD dwRes = ::WaitForSingleObject(pRequest->m_hKillEvent, 5*1000);

if (dwRes == WAIT_OBJECT_0) 
{
//重置线程结束事件并跳出循环,不再发送请求
                                ::ResetEvent(pRequest->m_hKillEvent);
break;
}

TRACE("update realtime thread-thread continue!\n");
} while(TRUE);
}
catch (CException* e) { CString strMsg;
e->GetErrorMessage(strMsg.GetBufferSetLength(MAX_PATH), MAX_PATH);
strMsg.ReleaseBuffer();
TRACE("send function exception. %s\n", strMsg); uRes = -1;
}        //退出该线程
::SetEvent(pRequest->m_hExitEvent);
return uRes;
}所有的HTTP请求发送和响应结果获取操作均在SendEx函数中完成,由于需要,该请求的发送和结果的获取需采用异步的方式完成,其代码如下:
CMemFile* CHttpDownRequest::SendEx(CString strUrl)
{
   m_bAllRead = FALSE;
   //创建会话句柄,设置异步标识
   m_hSession =::InternetOpen("AscRead",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,INTERNET_FLAG_ASYNC);
   //设置回调函数
   ::InternetSetStatusCallback(m_hSession,AsyncInternetCallback);
   //打开指定的URL
   m_hFile = ::InternetOpenUrl(m_hSession,strUrl,NULL,NULL, INTERNET_FLAG_RELOAD |  
                                                             INTERNET_FLAG_NO_CACHE_WRITE,1);
   //检测请求句柄是否已经完成
   if (m_hFile == NULL)
   {
//正在等待异步读取数据
if (ERROR_IO_PENDING == ::GetLastError())
{
        //等待10s超时,超时则直接关闭会话信息
        if (WAIT_OBJECT_0 != ::WaitForSingleObject(m_hReadComplete,10*1000))
{
//超时或读取错误,则关闭连接句柄
::InternetCloseHandle(m_hFile);
::InternetSetStatusCallback(m_hSession,NULL);
::InternetCloseHandle(m_hSession);
return NULL;
}
         }
 else    //其他错误,读取失败
{
//关闭连接句柄
::InternetCloseHandle(m_hFile);
::InternetSetStatusCallback(m_hSession,NULL);
::InternetCloseHandle(m_hSession);
return NULL;
}
    }
    
    //InternetOpenUrl执行返回请求句柄直接成功或异步读取完成,则开始读取返回的数据结果
    BYTE finalbuff[10*1024];
    DWORD tolReadBuff = 0;
    DWORD dwBytesRead =0;
    DWORD BuffLength = sizeof(finalbuff);
    FillMemory(finalbuff,BuffLength,0);
    //循环读取
    do 
    {
BYTE resultbuff[1024];
INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
FillMemory(&ib,sizeof(ib),0);
ib.lpvBuffer = resultbuff;
ib.dwBufferLength = sizeof(resultbuff);
//异步读取(注:该处执行出错)
if(!::InternetReadFileEx(m_hFile,&ib,IRF_ASYNC,1))
{
    //异步读取操作正在执行中,则等待读取操作完成
            if (::GetLastError() == ERROR_IO_PENDING)
    {
::WaitForSingleObject(m_hReadComplete, INFINITE);
    }
    else   //其他错误(出错时进入该代码段,GetLastError返回 87 参数不正确)
   {
TRACE("InternetReadFileEx failed! error code: %d\n",::GetLastError());
break;
    }
}

if (tolReadBuff > BuffLength)
    break;
        //将异步读取的数据移动至缓存数据区
memmove(&finalbuff[tolReadBuff],resultbuff,ib.dwBufferLength);
tolReadBuff += ib.dwBufferLength;

        //异步读取数据完成,则退出循环
if (ib.dwBufferLength == 0)
    m_bAllRead = TRUE;    } while (m_bAllRead == FALSE);
    
    //最后关闭相应的连接句柄
    ::InternetCloseHandle(m_hFile);
    ::InternetSetStatusCallback(m_hSession,NULL);
    ::InternetCloseHandle(m_hSession);

    if (tolReadBuff == 0)
return NULL;
    else
return new CMemFile(finalbuff,tolReadBuff,0);
  
}响应异步操作的回调函数如下:
void CALLBACK CHttpDownRequest::AsyncInternetCallback(HINTERNET hInternet,DWORD dwContext,DWORD dwInternetStatus,LPVOID lpvStatusInformation,DWORD dwStatusInformationLength)
{
    //检测上下文环境
    switch (dwContext)
    {
case 1:
{
    //检测状态
            switch (dwInternetStatus)
    {
       case INTERNET_STATUS_HANDLE_CREATED:
      {
INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpvStatusInformation;
//设置句柄
                m_hFile = (HINTERNET)pAsyncRes->dwResult;
      }
      break;
      case INTERNET_STATUS_RESPONSE_RECEIVED:
      {
        DWORD *dwBytesReceived = (DWORD*)lpvStatusInformation;
        if (*dwBytesReceived == 0)
          //设置读取完成标识为真
                  m_bAllRead = TRUE;
      }
      break;
     case INTERNET_STATUS_REQUEST_COMPLETE:
     {
       INTERNET_ASYNC_RESULT *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpvStatusInformation;
       if (pAsyncRes->dwError == ERROR_SUCCESS)
       {
  TRACE("Context 1 Callback: request complete!\n");
       }
       else
       {
  TRACE("Context 1 Callback: request bad error! dwerror:%d\n",pAsyncRes->dwError);
        }
               //请求完成,设置请求成功事件
       ::SetEvent(m_hReadComplete);
     }
     break;
  }
        }
break;
        //其他上下文环境
        default:
        break;
}我运行调试时,发生错误,主要错误为:
InternetReadFileEx(m_hFile,&ib,IRF_ASYNC,1)返回为FALSE,但是::GetLastError并没有返回ERROR_IO_PENDING,而是直接返回代码87,意思是参数不正确。但该函数的几个参数相对简单,最有可能出错的就是m_hFile了。
但小弟实在不知道是哪里出错了,请各位大哥帮忙看看!谢谢了!小弟分不多,感激了。另外:跟踪回调函数输出,其输出:
Context 1 Callback: request bad error! dwerror:12017
MSND上也没有查到12017代表什么意思。

解决方案 »

  1.   

    开发;卓越呼叫中心、三农热线”语音农业综合信息服务平台、卓越办公自动化软件、卓越电厂MIS系统、卓越客户关系管理系统、卓越网站制作、卓越医疗信息管理系统;沈阳卓越科技有限公司;www.excellence-tech.com
      

  2.   

    开发;卓越呼叫中心、三农热线”语音农业综合信息服务平台、卓越办公自动化软件、卓越电厂MIS系统、卓越客户关系管理系统、卓越网站制作、卓越医疗信息管理系统;沈阳卓越科技有限公司;http://www.excellence-tech.com
      

  3.   

    两天了,都没人进来,算了,揭帖了。
    这个问题我采用MSDN上的辅助线程的办法变通了一下,可以满足我的需求了。继续学习中。
      

  4.   

    INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
    FillMemory(&ib,sizeof(ib),0);你设置的size被第二句冲掉了。