Symbian(RSocket DownLoad)模拟HTTP下载
前面我们介绍了用平台的HTTP引擎来实现下载.
今天我们来看看如何用RSocket来实现下载.
接入点的部分我们已经在前面介绍完了.
相关部分的处理和实现我们不在提及.
好让我们来看看如何实现的!!嘎嘎!!
首先让我们来看看如何组装请求头
//Get Http Request
void CWebClientEngine::StartGetClient(const TDesC8& aURL, TInt size)
{
Cancel();
iSocket.Close();
iResolver.Close();
iSecondUrl.Copy(aURL);
iDownloadSize = size;
curSizeL = size+MAXDOWNLOADSIZE;
TUriParser8 m_oUri;
m_oUri.Parse(iSecondUrl);
const TDesC8& sScheme=m_oUri.Extract(EUriScheme);
const TDesC8& sHost=m_oUri.Extract(EUriHost);
const TDesC8& sPort=m_oUri.Extract(EUriPort);
const TDesC8& sPath=m_oUri.Extract(EUriPath);
if (!isWap)//如果是NET接入点
{
iServerName.Copy(sHost);
}
else//如果是WAP接入点,设置代理
{
#ifdef _DEBUG
iServerName.Copy(sHost);
#else
iServerName.Copy(_L("10.0.0.172"));
#endif
}
if (sPort.Length() == 0)//端口
{
port = 80;
}
else
{
TLex8 iLex;
iLex = sPort;
iLex.Val(port);
if(port == 0)
{
port = 80;
}
}
//组装HTTP请求头
if (iRequest)
{
delete iRequest;
iRequest = NULL;
}
iRequest = HBufC8::NewL(1024);
iRequest->Des().AppendFormat(_L8("GET %S HTTP/1.1/r/n"),&iSecondUrl);
#ifdef _DEBUG
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
// iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
#else
if(isWap)
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
}
else
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
}
#endif
iRequest->Des().AppendFormat(_L8("X-Online-Host:%S/r/n"),&sHost);
iRequest->Des().Append(_L8("User-Agent: myhttpClient 1.0/r/n"));
//在请求头里设置断点续传
iRequest->Des().Append(_L8("Accept: */*/r/nRange: bytes="));
iRequest->Des().AppendNum(size);
iRequest->Des().Append(_L8("-"));
iRequest->Des().AppendNum(size+MAXDOWNLOADSIZE);
iRequest->Des().Append(_L8("/r/n"));
iRequest->Des().Append(_L8("Connection: Close/r/n/r/n"));
//dns 解析
User::LeaveIfError(iResolver.Open(iSockServer, KAfInet, KProtocolInetTcp,
iConnection));
iResolver.GetByName(iServerName, iHostAddress, iStatus);
iState = EResolving;
isRunning = true;
SetActive();
}
//POST 请求
void CWebClientEngine::StartPostClient(const TDesC8& aURL,int size)
{
Cancel();
iSocket.Close();
iResolver.Close();
iSecondUrl.Copy(aURL);
iDownloadSize = size;
curSizeL = size+MAXDOWNLOADSIZE;
TUriParser8 m_oUri;
m_oUri.Parse(iSecondUrl);
const TDesC8& sScheme=m_oUri.Extract(EUriScheme);
const TDesC8& sHost=m_oUri.Extract(EUriHost);
const TDesC8& sPort=m_oUri.Extract(EUriPort);
const TDesC8& sPath=m_oUri.Extract(EUriPath);
if (!isWap)
{
iServerName.Copy(sHost);
}
else//WAP接入点,设置代理
{
#ifdef _DEBUG
iServerName.Copy(sHost);
#else
iServerName.Copy(_L("10.0.0.172"));
#endif
}
if (sPort.Length() == 0)
{
port = 80;
}
else
{
TLex8 iLex;
iLex = sPort;
iLex.Val(port);
if(port == 0)
{
port = 80;
}
}
//组装HTTP请求头
if (iRequest)
{
delete iRequest;
iRequest = NULL;
}
iRequest = HBufC8::NewL(1024);
iRequest->Des().AppendFormat(_L8("POST %S HTTP/1.1/r/n"),&iSecondUrl);
#ifdef _DEBUG
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
#else
if(isWap)
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
}
else
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
}
#endif
iRequest->Des().AppendFormat(_L8("X-Online-Host:%S/r/n"),&sHost);
iRequest->Des().Append(_L8("User-Agent: myhttpClient 1.0/r/n"));
iRequest->Des().Append(_L8("Accept: */*/r/nRange: bytes="));
//设置断点续传
iRequest->Des().AppendNum(size);
iRequest->Des().Append(_L8("-"));
iRequest->Des().AppendNum(size+MAXDOWNLOADSIZE);
iRequest->Des().Append(_L8("/r/n"));
iRequest->Des().Append(_L8("Content-Length: 0/r/n"));
iRequest->Des().Append(_L8("Cache-Control: no-cache/r/n"));
iRequest->Des().Append(_L8("Connection: Close/r/n/r/n"));
//dns 解析
User::LeaveIfError(iResolver.Open(iSockServer, KAfInet, KProtocolInetTcp,
iConnection));
iResolver.GetByName(iServerName, iHostAddress, iStatus);
iState = EResolving;
isRunning = true;
SetActive();
}
//好,请求部分完了之后,让我们来看看如何响应了.哈哈!!!!
void CWebClientEngine::RunL()
{
if (iStatus.Int() == KErrNone)
{
switch (iState)
{
case EResolving:
{
//域名解析完成后
//连接HOST
User::LeaveIfError(iSocket.Open(iSockServer, KAfInet,
KSockStream,
KProtocolInetTcp, iConnection));
TInetAddr address;
address = iHostAddress().iAddr;
address.SetPort(port);
iState = EConnecting;
iSocket.Connect(address, iStatus) ;
SetActive();
}
break;
case EConnecting:
{
//连接成功后,发送请求
iSocket.Write(iRequest->Des(), iStatus) ;
iState = ESending;
SetActive();
}
break;
case ESending:
{
//请求成功后,准备接收数据
iResponseChunk.Zero() ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus,
iResponseChunkSizePkg) ;
iState = EReceiving;
SetActive();
}
break;
case EReceiving:
{
//接收数据
int errCode = 0;
if (CheckRecv(iResponseChunk))//判断是否为移动拦截页
{
//解析数据
if (ParseWebFileInfo(iResponseChunk, SizeL, HrdLen,
errCode))
{
if (HandleStatus(errCode))
{
return;
}
//写文件
// SizeL += iDownloadSize;
iDownloadSize+=iResponseChunk.Length()-
HrdLen;
iObserver->HandleHttpProgress(SizeL,
iDownloadSize);
iObserver->HandleWebData(iResponseChunk.Mid
(HrdLen));
}
else
{
//写文件
iDownloadSize+=iResponseChunk.Length();
iObserver->HandleHttpProgress(SizeL,
iDownloadSize);
iObserver->HandleWebData(iResponseChunk);
}
}
else
{//移动页进行二次请求
if (SecLink(iSecondUrl))
return;
}
iState = EReceiveMore;
iTimer.After(iStatus, 10000);
StartTimer(30);
SetActive();
}
break;
case EReceiveMore:
if (SizeL == iDownloadSize||iDownloadSize == curSizeL+1)//判
断数据是否下载完成
{
if(iDownloadSize < SizeL)
{
if (SecLink(iSecondUrl))
return;
}
Cancel();
iState = EComplete;
iTimer.After(iStatus, 1000);
StopTimer();
SetActive();
}
else//如果没有下载完成,继续准备接收数据
{
iState = EReceiving;
iResponseChunk.Zero() ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus,
iResponseChunkSizePkg) ;
SetActive();
}
break;
case EComplete:
{
//下载完成
iObserver->HandleWebDataCompleteL();
}
break;
}
}
}
//最重要的部分消息响应流程介绍完了.
//让我们来看看如何解析消息头的.哈哈.
_LIT8(KHttpHdrDiv, "/r/n");
_LIT8(KHttpHdrEnd, "/r/n/r/n");
TBool CWebClientEngine::ParseWebFileInfo(const TDesC8& recv_buf,
TInt& file_length, TInt& jump_len, TInt& status)
{
TBuf8<64> tmp_field;
TBuf8<64> tmp_end;
TBuf8<1024> tmp_str;
int find_pos;
status = 0;
//取状态码
tmp_field.Copy(_L8("HTTP/1.1 "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
status = Str2Int(tmp_str.Left(3));
//取长度
file_length = 0;
tmp_field.Copy(_L8("Content-Length: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
file_length = Str2Int(tmp_str);
//取总长度
tmp_field.Copy(_L8("Content-Range: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
{//取到
int pos = tmp_str.LocateReverse('/');
if(pos >= 0)
{
int length = tmp_str.Length() - pos - 1;
file_length = Str2Int(tmp_str.Right(length));
}
}
if (status == 302||status == 301)
{
//跳转地址
tmp_field.Copy(_L8("Location: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
if (LocationUrl)
{
delete LocationUrl;
LocationUrl = NULL;
}
LocationUrl = CompleteUrl(tmp_str);
}
// set the jump length
jump_len = 0;
find_pos = recv_buf.Find(KHttpHdrEnd) ;
if (find_pos != KErrNotFound)
{
tmp_str.Copy(KHttpHdrEnd) ;
jump_len = find_pos + tmp_str.Length() ;
}
return ETrue;
}
//整个框架的核心已经介绍完了.
以上代码适合SYMBIAN 2nd,3rd,5th三个平台通用.
前面我们介绍了用平台的HTTP引擎来实现下载.
今天我们来看看如何用RSocket来实现下载.
接入点的部分我们已经在前面介绍完了.
相关部分的处理和实现我们不在提及.
好让我们来看看如何实现的!!嘎嘎!!
首先让我们来看看如何组装请求头
//Get Http Request
void CWebClientEngine::StartGetClient(const TDesC8& aURL, TInt size)
{
Cancel();
iSocket.Close();
iResolver.Close();
iSecondUrl.Copy(aURL);
iDownloadSize = size;
curSizeL = size+MAXDOWNLOADSIZE;
TUriParser8 m_oUri;
m_oUri.Parse(iSecondUrl);
const TDesC8& sScheme=m_oUri.Extract(EUriScheme);
const TDesC8& sHost=m_oUri.Extract(EUriHost);
const TDesC8& sPort=m_oUri.Extract(EUriPort);
const TDesC8& sPath=m_oUri.Extract(EUriPath);
if (!isWap)//如果是NET接入点
{
iServerName.Copy(sHost);
}
else//如果是WAP接入点,设置代理
{
#ifdef _DEBUG
iServerName.Copy(sHost);
#else
iServerName.Copy(_L("10.0.0.172"));
#endif
}
if (sPort.Length() == 0)//端口
{
port = 80;
}
else
{
TLex8 iLex;
iLex = sPort;
iLex.Val(port);
if(port == 0)
{
port = 80;
}
}
//组装HTTP请求头
if (iRequest)
{
delete iRequest;
iRequest = NULL;
}
iRequest = HBufC8::NewL(1024);
iRequest->Des().AppendFormat(_L8("GET %S HTTP/1.1/r/n"),&iSecondUrl);
#ifdef _DEBUG
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
// iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
#else
if(isWap)
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
}
else
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
}
#endif
iRequest->Des().AppendFormat(_L8("X-Online-Host:%S/r/n"),&sHost);
iRequest->Des().Append(_L8("User-Agent: myhttpClient 1.0/r/n"));
//在请求头里设置断点续传
iRequest->Des().Append(_L8("Accept: */*/r/nRange: bytes="));
iRequest->Des().AppendNum(size);
iRequest->Des().Append(_L8("-"));
iRequest->Des().AppendNum(size+MAXDOWNLOADSIZE);
iRequest->Des().Append(_L8("/r/n"));
iRequest->Des().Append(_L8("Connection: Close/r/n/r/n"));
//dns 解析
User::LeaveIfError(iResolver.Open(iSockServer, KAfInet, KProtocolInetTcp,
iConnection));
iResolver.GetByName(iServerName, iHostAddress, iStatus);
iState = EResolving;
isRunning = true;
SetActive();
}
//POST 请求
void CWebClientEngine::StartPostClient(const TDesC8& aURL,int size)
{
Cancel();
iSocket.Close();
iResolver.Close();
iSecondUrl.Copy(aURL);
iDownloadSize = size;
curSizeL = size+MAXDOWNLOADSIZE;
TUriParser8 m_oUri;
m_oUri.Parse(iSecondUrl);
const TDesC8& sScheme=m_oUri.Extract(EUriScheme);
const TDesC8& sHost=m_oUri.Extract(EUriHost);
const TDesC8& sPort=m_oUri.Extract(EUriPort);
const TDesC8& sPath=m_oUri.Extract(EUriPath);
if (!isWap)
{
iServerName.Copy(sHost);
}
else//WAP接入点,设置代理
{
#ifdef _DEBUG
iServerName.Copy(sHost);
#else
iServerName.Copy(_L("10.0.0.172"));
#endif
}
if (sPort.Length() == 0)
{
port = 80;
}
else
{
TLex8 iLex;
iLex = sPort;
iLex.Val(port);
if(port == 0)
{
port = 80;
}
}
//组装HTTP请求头
if (iRequest)
{
delete iRequest;
iRequest = NULL;
}
iRequest = HBufC8::NewL(1024);
iRequest->Des().AppendFormat(_L8("POST %S HTTP/1.1/r/n"),&iSecondUrl);
#ifdef _DEBUG
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
#else
if(isWap)
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&_L8("10.0.0.172"));
}
else
{
iRequest->Des().AppendFormat(_L8("Host:%S/r/n"),&sHost);
}
#endif
iRequest->Des().AppendFormat(_L8("X-Online-Host:%S/r/n"),&sHost);
iRequest->Des().Append(_L8("User-Agent: myhttpClient 1.0/r/n"));
iRequest->Des().Append(_L8("Accept: */*/r/nRange: bytes="));
//设置断点续传
iRequest->Des().AppendNum(size);
iRequest->Des().Append(_L8("-"));
iRequest->Des().AppendNum(size+MAXDOWNLOADSIZE);
iRequest->Des().Append(_L8("/r/n"));
iRequest->Des().Append(_L8("Content-Length: 0/r/n"));
iRequest->Des().Append(_L8("Cache-Control: no-cache/r/n"));
iRequest->Des().Append(_L8("Connection: Close/r/n/r/n"));
//dns 解析
User::LeaveIfError(iResolver.Open(iSockServer, KAfInet, KProtocolInetTcp,
iConnection));
iResolver.GetByName(iServerName, iHostAddress, iStatus);
iState = EResolving;
isRunning = true;
SetActive();
}
//好,请求部分完了之后,让我们来看看如何响应了.哈哈!!!!
void CWebClientEngine::RunL()
{
if (iStatus.Int() == KErrNone)
{
switch (iState)
{
case EResolving:
{
//域名解析完成后
//连接HOST
User::LeaveIfError(iSocket.Open(iSockServer, KAfInet,
KSockStream,
KProtocolInetTcp, iConnection));
TInetAddr address;
address = iHostAddress().iAddr;
address.SetPort(port);
iState = EConnecting;
iSocket.Connect(address, iStatus) ;
SetActive();
}
break;
case EConnecting:
{
//连接成功后,发送请求
iSocket.Write(iRequest->Des(), iStatus) ;
iState = ESending;
SetActive();
}
break;
case ESending:
{
//请求成功后,准备接收数据
iResponseChunk.Zero() ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus,
iResponseChunkSizePkg) ;
iState = EReceiving;
SetActive();
}
break;
case EReceiving:
{
//接收数据
int errCode = 0;
if (CheckRecv(iResponseChunk))//判断是否为移动拦截页
{
//解析数据
if (ParseWebFileInfo(iResponseChunk, SizeL, HrdLen,
errCode))
{
if (HandleStatus(errCode))
{
return;
}
//写文件
// SizeL += iDownloadSize;
iDownloadSize+=iResponseChunk.Length()-
HrdLen;
iObserver->HandleHttpProgress(SizeL,
iDownloadSize);
iObserver->HandleWebData(iResponseChunk.Mid
(HrdLen));
}
else
{
//写文件
iDownloadSize+=iResponseChunk.Length();
iObserver->HandleHttpProgress(SizeL,
iDownloadSize);
iObserver->HandleWebData(iResponseChunk);
}
}
else
{//移动页进行二次请求
if (SecLink(iSecondUrl))
return;
}
iState = EReceiveMore;
iTimer.After(iStatus, 10000);
StartTimer(30);
SetActive();
}
break;
case EReceiveMore:
if (SizeL == iDownloadSize||iDownloadSize == curSizeL+1)//判
断数据是否下载完成
{
if(iDownloadSize < SizeL)
{
if (SecLink(iSecondUrl))
return;
}
Cancel();
iState = EComplete;
iTimer.After(iStatus, 1000);
StopTimer();
SetActive();
}
else//如果没有下载完成,继续准备接收数据
{
iState = EReceiving;
iResponseChunk.Zero() ;
iSocket.RecvOneOrMore(iResponseChunk, 0, iStatus,
iResponseChunkSizePkg) ;
SetActive();
}
break;
case EComplete:
{
//下载完成
iObserver->HandleWebDataCompleteL();
}
break;
}
}
}
//最重要的部分消息响应流程介绍完了.
//让我们来看看如何解析消息头的.哈哈.
_LIT8(KHttpHdrDiv, "/r/n");
_LIT8(KHttpHdrEnd, "/r/n/r/n");
TBool CWebClientEngine::ParseWebFileInfo(const TDesC8& recv_buf,
TInt& file_length, TInt& jump_len, TInt& status)
{
TBuf8<64> tmp_field;
TBuf8<64> tmp_end;
TBuf8<1024> tmp_str;
int find_pos;
status = 0;
//取状态码
tmp_field.Copy(_L8("HTTP/1.1 "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
status = Str2Int(tmp_str.Left(3));
//取长度
file_length = 0;
tmp_field.Copy(_L8("Content-Length: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
file_length = Str2Int(tmp_str);
//取总长度
tmp_field.Copy(_L8("Content-Range: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
{//取到
int pos = tmp_str.LocateReverse('/');
if(pos >= 0)
{
int length = tmp_str.Length() - pos - 1;
file_length = Str2Int(tmp_str.Right(length));
}
}
if (status == 302||status == 301)
{
//跳转地址
tmp_field.Copy(_L8("Location: "));
tmp_end.Copy(KHttpHdrDiv) ;
if (!GetRespField(recv_buf, tmp_field, tmp_end, tmp_str))
return EFalse;
if (LocationUrl)
{
delete LocationUrl;
LocationUrl = NULL;
}
LocationUrl = CompleteUrl(tmp_str);
}
// set the jump length
jump_len = 0;
find_pos = recv_buf.Find(KHttpHdrEnd) ;
if (find_pos != KErrNotFound)
{
tmp_str.Copy(KHttpHdrEnd) ;
jump_len = find_pos + tmp_str.Length() ;
}
return ETrue;
}
//整个框架的核心已经介绍完了.
以上代码适合SYMBIAN 2nd,3rd,5th三个平台通用.