Symbian(Http DownLoad)Http引擎下载
前面二篇blog介绍了关于接入点的相关情况
今天让我们来看看下载是如何处理的
其实在SYMBIAN平台实现下载方式较多
比如直接用系统提供的HTTP引擎
比如有SOCKET模拟HTTP来实现
今天我们主要谈谈用平台的HTTP引警是如何实现的
也会在接下来的通信编程中聊聊socket模拟HTTP下载.
其实WIKI上给我们提供了一个关于HTTP下载的很好的例子.
并且网上也有很多关于这方面的资料.
我将主要谈谈比较关键的地方希望对后来的学习的朋友有一些帮助.
其实要完成整个HTTP下载官方提供的例子是不够的.
官方的例子只能让我们了解API的使用流程.
我们还需要处理各种异常,比如超时,比如跳转等等.
我们还要站在用户的角度去处理比如走WAP代理,比如断点续传等等.
好让我们少费话了直接进入主题吧!!嘎嘎!!!
首先介绍以下三个主要类:
//处理HTTP事物中的相关事件
//比如响应消息头,消息体,各种异常处理等
MHTTPTransactionCallback
//HTTP会话,建立客户端于内核的会话
RHTTPSession
//在会话的基础上建立下载事物
//一个http session可以有多个Transaction
//要实现多个事物同时进行必须要建立多个http session
RHTTPTransaction
经过上述基本介绍后,让我们看看具体的实现吧!!
//GET 请求
void CWebClientEngine::HTTPGetL(const TDesC8& aUri)
{
iDownloadSize = 0;
bHttpGetOrPost = ETrue;
//自己设置计时器,为超时作准备
StartTimer(30);
//为了二次连接,在WAP代理时首次连接会有移动拦截页回来
//这样可以直接把当前连接再请求一次,即可以解决问题.
iSecondUrl.Copy(aUri);
TUriParser8 uri;
uri.Parse(aUri);
#ifndef _DEBUG//不在DEBUG的情况下
if (bIAPIsWap)//如果是WAP接入点,需要设置WAP代理
{
//中国特色,不要报怨.
//改变不了社会,就加代码.嘎嘎!!
TBuf8<20> aProxy8(_L8("10.0.0.172:80"));
RStringF iPrxAddr = iSession.StringPool().OpenFStringL(aProxy8);
CleanupClosePushL(iPrxAddr);
THTTPHdrVal iPrxUsage(iSession.StringPool().StringF
(HTTP::EUseProxy,RHTTPSession::GetTable()));
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyUsage,RHTTPSession::GetTable()), iPrxUsage);
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyAddress,RHTTPSession::GetTable()), iPrxAddr);
CleanupStack::PopAndDestroy();
}
#endif
// Get request method string for HTTP GET
RStringF method = iSession.StringPool().StringF(HTTP::EGET,
RHTTPSession::GetTable());
// Open transaction with previous method and parsed uri. This class will
// receive transaction events in MHFRunL and MHFRunError.
iTransaction = iSession.OpenTransactionL(uri, *this, method);
// Set headers for request; user agent and accepted content type
RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);//设置UA
SetHeaderL(hdr, HTTP::EAccept, KAccept);//设置accept
//设置代码续传
TBuf8<64> sizeStr;
sizeStr.Format (_L8("bytes=%d-"),iDownloadSize);
sizeStr.AppendFormat (_L8("%d"),curSizeL);
SetHeaderL (hdr, HTTP::ERange, sizeStr);
// Submit the transaction. After this the framework will give transaction
// events via MHFRunL and MHFRunError.
iTransaction.SubmitL();//启动请求.请法度是一个异步的过程.
//请求完成后,会在MHTTPTransactionCallback方法回调相关的事件.
iRunning = ETrue;
}
//POST 请求
void CWebClientEngine::HTTPPostL(const TDesC8& aUri, const TDesC8& aBody)
{
iDownloadSize = 0;
bHttpGetOrPost = EFalse;
StartTimer(30);
iSecondUrl.Copy(aUri);
// Parse string to URI (as defined in RFC2396)
TUriParser8 uri;
uri.Parse(aUri);
delete iPostData;
iPostData = aBody.AllocL();
#ifndef _DEBUG
if (bIAPIsWap)//设置WAP代理
{
TBuf8<20> aProxy8(_L8("10.0.0.172:80"));
RStringF iPrxAddr = iSession.StringPool().OpenFStringL(aProxy8);
CleanupClosePushL(iPrxAddr);
THTTPHdrVal iPrxUsage(iSession.StringPool().StringF
(HTTP::EUseProxy,RHTTPSession::GetTable()));
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyUsage,RHTTPSession::GetTable()), iPrxUsage);
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyAddress,RHTTPSession::GetTable()), iPrxAddr);
CleanupStack::PopAndDestroy();
}
#endif
RStringF method = iSession.StringPool().StringF(HTTP::EPOST,
RHTTPSession::GetTable());
// Open transaction with previous method and parsed uri. This class will
// receive transaction events in MHFRunL and MHFRunError.
iTransaction = iSession.OpenTransactionL(uri, *this, method);
// Set headers for request; user agent and accepted content type
RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
SetHeaderL(hdr, HTTP::EAccept, KAccept);
SetHeaderL( hdr, HTTP::EContentType, _L8("text/xml"));
//设置代码续传
TBuf8<64> sizeStr;
sizeStr.Format (_L8("bytes=%d-"),iDownloadSize);
sizeStr.AppendFormat (_L8("%d"),curSizeL);
SetHeaderL (hdr, HTTP::ERange, sizeStr);
MHTTPDataSupplier* dataSupplier = this;
iTransaction.Request().SetBody(*dataSupplier);
// Submit the transaction. After this the framework will give transaction
// events via MHFRunL and MHFRunError.
iTransaction.SubmitL();
iRunning = ETrue;
}
//请求完成后,事物的相关事件都会回调
void CWebClientEngine::MHFRunL(RHTTPTransaction aTransaction,
const THTTPEvent& aEvent)
{
switch (aEvent.iStatus)
{
//响应消息头
case THTTPEvent::EGotResponseHeaders:
{
RHTTPResponse resp = aTransaction.Response();
TInt status = resp.StatusCode();
if (status == 200 || status == 206)
{
//成功连接的情况下,解析头.
DumpRespHeadersL(aTransaction);
iObserver->HandleWebDataStart();
}
else if (status >= 300 && status <= 399)
{
iRunning = EFalse;
//发生跳转时,得到跳转地址
GetLocationL(aTransaction);
iDownloadSize = 0;
//得到跳转地址后,重新请求
StartGetClient(m_Location,iDownloadSize);
break;
}
else
{
//发生异常,关闭事物
iTransaction.Close();
iRunning = EFalse;
break;
}
}
break;
case THTTPEvent::EGotResponseBodyData:
{
//响应消息体
// Get the body data supplier
MHTTPDataSupplier* body = aTransaction.Response().Body();
TPtrC8 dataChunk;
TBool isLast = body->GetNextDataPart(dataChunk);
RLog::LogPoor(_L("isLast = "),isLast);
DataLength = dataChunk.Length();
bIsReciveData = ETrue;
if(bIAPIsWap)//如果是WAP接入点.我们需要判断移动拦截页面
{
//如果是移动拦截页,再次请求
TBool err = CheckRecv(dataChunk);
RLog::LogPoor(_L("err = "),err);
if(err == false)
{
body->ReleaseData();
CancelTransactionL();
//重新请求分二种情况
//GET请求,POST请求
if (bHttpGetOrPost)//get方法
{
iDownloadSize = 0;
StartGetClient(iSecondUrl,iDownloadSize);
}
else
{
HTTPPostL(iSecondUrl,*DataSecondPost);
}
break;
}
}
iObserver->HandleWebData(dataChunk);
body->ReleaseData();
iDownloadSize += DataLength;
StartTimer(30);//30s超时
RLog::LogPoor(_L("Exit EGotResponseBodyData"));
}
break;
case THTTPEvent::EResponseComplete:
{
//响应服务器完成
RLog::LogPoor(_L("EResponseComplete"));
}
break;
case THTTPEvent::ESucceeded:
{
//整个事物成功处理
RLog::LogPoor(_L("ESucceeded"));
RLog::LogPoor(_L("iDownloadSize = "),iDownloadSize);
if(iDownloadSize < iFileLength - 1)
{
aTransaction.Close();
StartGetClient(iSecondUrl,iDownloadSize);
break;
}
// Transaction can be closed now. It's not needed anymore.
aTransaction.Close();
StopTimer();
iObserver->HandleWebDataCompleteL();
bIsReciveData = ETrue;
iRunning = EFalse;
}
break;
case THTTPEvent::EFailed:
{
//异常出现
RLog::LogPoor(_L("EFailed"));
aTransaction.Close();
StopTimer();
iObserver->HandleError();
iRunning = EFalse;
iDownloadSize = 0;
}
break;
default:
{
TInt err = aEvent.iStatus;
RLog::LogPoor(_L("err = "),err);
if (aEvent.iStatus < 0)
{
aTransaction.Close();
StopTimer();
iObserver->HandleError();
iRunning = EFalse;
}
}
break;
}
}
经过上述处理就可以完成整个下载流程了.
以上代码适合SYMBIAN 2nd,3rd,5th三个平台通用.
前面二篇blog介绍了关于接入点的相关情况
今天让我们来看看下载是如何处理的
其实在SYMBIAN平台实现下载方式较多
比如直接用系统提供的HTTP引擎
比如有SOCKET模拟HTTP来实现
今天我们主要谈谈用平台的HTTP引警是如何实现的
也会在接下来的通信编程中聊聊socket模拟HTTP下载.
其实WIKI上给我们提供了一个关于HTTP下载的很好的例子.
并且网上也有很多关于这方面的资料.
我将主要谈谈比较关键的地方希望对后来的学习的朋友有一些帮助.
其实要完成整个HTTP下载官方提供的例子是不够的.
官方的例子只能让我们了解API的使用流程.
我们还需要处理各种异常,比如超时,比如跳转等等.
我们还要站在用户的角度去处理比如走WAP代理,比如断点续传等等.
好让我们少费话了直接进入主题吧!!嘎嘎!!!
首先介绍以下三个主要类:
//处理HTTP事物中的相关事件
//比如响应消息头,消息体,各种异常处理等
MHTTPTransactionCallback
//HTTP会话,建立客户端于内核的会话
RHTTPSession
//在会话的基础上建立下载事物
//一个http session可以有多个Transaction
//要实现多个事物同时进行必须要建立多个http session
RHTTPTransaction
经过上述基本介绍后,让我们看看具体的实现吧!!
//GET 请求
void CWebClientEngine::HTTPGetL(const TDesC8& aUri)
{
iDownloadSize = 0;
bHttpGetOrPost = ETrue;
//自己设置计时器,为超时作准备
StartTimer(30);
//为了二次连接,在WAP代理时首次连接会有移动拦截页回来
//这样可以直接把当前连接再请求一次,即可以解决问题.
iSecondUrl.Copy(aUri);
TUriParser8 uri;
uri.Parse(aUri);
#ifndef _DEBUG//不在DEBUG的情况下
if (bIAPIsWap)//如果是WAP接入点,需要设置WAP代理
{
//中国特色,不要报怨.
//改变不了社会,就加代码.嘎嘎!!
TBuf8<20> aProxy8(_L8("10.0.0.172:80"));
RStringF iPrxAddr = iSession.StringPool().OpenFStringL(aProxy8);
CleanupClosePushL(iPrxAddr);
THTTPHdrVal iPrxUsage(iSession.StringPool().StringF
(HTTP::EUseProxy,RHTTPSession::GetTable()));
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyUsage,RHTTPSession::GetTable()), iPrxUsage);
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyAddress,RHTTPSession::GetTable()), iPrxAddr);
CleanupStack::PopAndDestroy();
}
#endif
// Get request method string for HTTP GET
RStringF method = iSession.StringPool().StringF(HTTP::EGET,
RHTTPSession::GetTable());
// Open transaction with previous method and parsed uri. This class will
// receive transaction events in MHFRunL and MHFRunError.
iTransaction = iSession.OpenTransactionL(uri, *this, method);
// Set headers for request; user agent and accepted content type
RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);//设置UA
SetHeaderL(hdr, HTTP::EAccept, KAccept);//设置accept
//设置代码续传
TBuf8<64> sizeStr;
sizeStr.Format (_L8("bytes=%d-"),iDownloadSize);
sizeStr.AppendFormat (_L8("%d"),curSizeL);
SetHeaderL (hdr, HTTP::ERange, sizeStr);
// Submit the transaction. After this the framework will give transaction
// events via MHFRunL and MHFRunError.
iTransaction.SubmitL();//启动请求.请法度是一个异步的过程.
//请求完成后,会在MHTTPTransactionCallback方法回调相关的事件.
iRunning = ETrue;
}
//POST 请求
void CWebClientEngine::HTTPPostL(const TDesC8& aUri, const TDesC8& aBody)
{
iDownloadSize = 0;
bHttpGetOrPost = EFalse;
StartTimer(30);
iSecondUrl.Copy(aUri);
// Parse string to URI (as defined in RFC2396)
TUriParser8 uri;
uri.Parse(aUri);
delete iPostData;
iPostData = aBody.AllocL();
#ifndef _DEBUG
if (bIAPIsWap)//设置WAP代理
{
TBuf8<20> aProxy8(_L8("10.0.0.172:80"));
RStringF iPrxAddr = iSession.StringPool().OpenFStringL(aProxy8);
CleanupClosePushL(iPrxAddr);
THTTPHdrVal iPrxUsage(iSession.StringPool().StringF
(HTTP::EUseProxy,RHTTPSession::GetTable()));
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyUsage,RHTTPSession::GetTable()), iPrxUsage);
iSession.ConnectionInfo().SetPropertyL(iSession.StringPool().StringF
(HTTP::EProxyAddress,RHTTPSession::GetTable()), iPrxAddr);
CleanupStack::PopAndDestroy();
}
#endif
RStringF method = iSession.StringPool().StringF(HTTP::EPOST,
RHTTPSession::GetTable());
// Open transaction with previous method and parsed uri. This class will
// receive transaction events in MHFRunL and MHFRunError.
iTransaction = iSession.OpenTransactionL(uri, *this, method);
// Set headers for request; user agent and accepted content type
RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
SetHeaderL(hdr, HTTP::EAccept, KAccept);
SetHeaderL( hdr, HTTP::EContentType, _L8("text/xml"));
//设置代码续传
TBuf8<64> sizeStr;
sizeStr.Format (_L8("bytes=%d-"),iDownloadSize);
sizeStr.AppendFormat (_L8("%d"),curSizeL);
SetHeaderL (hdr, HTTP::ERange, sizeStr);
MHTTPDataSupplier* dataSupplier = this;
iTransaction.Request().SetBody(*dataSupplier);
// Submit the transaction. After this the framework will give transaction
// events via MHFRunL and MHFRunError.
iTransaction.SubmitL();
iRunning = ETrue;
}
//请求完成后,事物的相关事件都会回调
void CWebClientEngine::MHFRunL(RHTTPTransaction aTransaction,
const THTTPEvent& aEvent)
{
switch (aEvent.iStatus)
{
//响应消息头
case THTTPEvent::EGotResponseHeaders:
{
RHTTPResponse resp = aTransaction.Response();
TInt status = resp.StatusCode();
if (status == 200 || status == 206)
{
//成功连接的情况下,解析头.
DumpRespHeadersL(aTransaction);
iObserver->HandleWebDataStart();
}
else if (status >= 300 && status <= 399)
{
iRunning = EFalse;
//发生跳转时,得到跳转地址
GetLocationL(aTransaction);
iDownloadSize = 0;
//得到跳转地址后,重新请求
StartGetClient(m_Location,iDownloadSize);
break;
}
else
{
//发生异常,关闭事物
iTransaction.Close();
iRunning = EFalse;
break;
}
}
break;
case THTTPEvent::EGotResponseBodyData:
{
//响应消息体
// Get the body data supplier
MHTTPDataSupplier* body = aTransaction.Response().Body();
TPtrC8 dataChunk;
TBool isLast = body->GetNextDataPart(dataChunk);
RLog::LogPoor(_L("isLast = "),isLast);
DataLength = dataChunk.Length();
bIsReciveData = ETrue;
if(bIAPIsWap)//如果是WAP接入点.我们需要判断移动拦截页面
{
//如果是移动拦截页,再次请求
TBool err = CheckRecv(dataChunk);
RLog::LogPoor(_L("err = "),err);
if(err == false)
{
body->ReleaseData();
CancelTransactionL();
//重新请求分二种情况
//GET请求,POST请求
if (bHttpGetOrPost)//get方法
{
iDownloadSize = 0;
StartGetClient(iSecondUrl,iDownloadSize);
}
else
{
HTTPPostL(iSecondUrl,*DataSecondPost);
}
break;
}
}
iObserver->HandleWebData(dataChunk);
body->ReleaseData();
iDownloadSize += DataLength;
StartTimer(30);//30s超时
RLog::LogPoor(_L("Exit EGotResponseBodyData"));
}
break;
case THTTPEvent::EResponseComplete:
{
//响应服务器完成
RLog::LogPoor(_L("EResponseComplete"));
}
break;
case THTTPEvent::ESucceeded:
{
//整个事物成功处理
RLog::LogPoor(_L("ESucceeded"));
RLog::LogPoor(_L("iDownloadSize = "),iDownloadSize);
if(iDownloadSize < iFileLength - 1)
{
aTransaction.Close();
StartGetClient(iSecondUrl,iDownloadSize);
break;
}
// Transaction can be closed now. It's not needed anymore.
aTransaction.Close();
StopTimer();
iObserver->HandleWebDataCompleteL();
bIsReciveData = ETrue;
iRunning = EFalse;
}
break;
case THTTPEvent::EFailed:
{
//异常出现
RLog::LogPoor(_L("EFailed"));
aTransaction.Close();
StopTimer();
iObserver->HandleError();
iRunning = EFalse;
iDownloadSize = 0;
}
break;
default:
{
TInt err = aEvent.iStatus;
RLog::LogPoor(_L("err = "),err);
if (aEvent.iStatus < 0)
{
aTransaction.Close();
StopTimer();
iObserver->HandleError();
iRunning = EFalse;
}
}
break;
}
}
经过上述处理就可以完成整个下载流程了.
以上代码适合SYMBIAN 2nd,3rd,5th三个平台通用.