📄 symbian 2nd支持cmnet和cmwap的断点续传的rsocket实现.htm
字号:
<DIV>class CM5HttpDown : public CBase, public MUINotifier
{<BR>protected:<BR> // socket
data<BR>
TInt
m_down_type ; // 下载的类型,是cmnet还是cmwap<BR>
CSocketsEngine * m_sock_eng ; //
常规的socket engine<BR>
TBool
m_running ; // 标志量用于标明下载是否开始<BR>
TBool
m_is_first_resp ; // 由于移动对于cmwap有推送页面,这个标记就是用来</DIV>
<DIV> //
检查第一次Get的结果是否为推送页面,hoho,</DIV>
<DIV>
// 如果是的话。。。屏蔽啦。。。<BR>
TInt
m_web_port ;
// 端口了,默认是80端口<BR>
TInt
m_total_bytes ; //
这里就是保存数据包总共有多少字节<BR>
TInt
m_recv_bytes; // 这里保存了已经下载了多少字节,用于断点续传</DIV>
<DIV> </DIV>
<DIV>//
下面是发送缓冲区定义以及一些地址字符串定义<BR> TBuf8<HTTP_SEND_BUF_LEN>
m_send_buf ; <BR> TBuf8<HTTP_TEMP_BUF_LEN> m_web_addr ;
<BR> TBuf8<HTTP_TEMP_BUF_LEN> m_web_fname ; </DIV>
<DIV> M5HttpDownNotifier& m_m5_notifier
; // 用于给调用者回调,收到数据<BR> <BR>public:
// 定义了ui notify的状态打印相关的函数<BR> void PrintNotify(const
TDesC& aMessage, TUint aAttributes = 0) ;<BR> void
RecvNotify(const TDesC8& aMessage) ;<BR> void
ErrorNotify(const TDesC& aErrMessage, TInt aErrCode) ;
<BR> void SetStatus(const TDesC& aStatus) ; </DIV>
<DIV> </DIV>
<DIV>protected:</DIV>
<DIV> // 把字符串转换成整数的函数<BR> TInt Str2Int(const TDesC8
& s) ; </DIV>
<DIV> </DIV>
<DIV> // 检查收到的数据是移动的推送页面呢,还是正常的数据<BR> TBool
CheckRecv(const TDesC8& recv_buf) ; </DIV>
<DIV> </DIV>
<DIV> // 解析调用者传入的uri,便于把断点续传的头取出来,例如要下载的地址为:</DIV>
<DIV> // <A
href="http://www.5mbox.com/bbs/mp1.mp3">www.5mbox.com/bbs/mp1.mp3</A>,那么就需要把这个uri分割为两部分:</DIV>
<DIV> // <A
href="http://www.5mbox.com/">http://www.5mbox.com/</A>域名,用于往这台服务器上发送下载请求;/bbs/mp1.mp3文件名,用于构建</DIV>
<DIV> //
断点续传的请求包的包头,所以这个函数也很重要喔!!<BR> TBool
ParseUri(TDesC8& uri, TDes8& web_addr, TDes8&
web_fname, TInt& web_port) ; </DIV>
<DIV> </DIV>
<DIV> //
解析从服务器返回回来的结果,可以得到文件的大小,以及需要跳过的数据长度</DIV>
<DIV> //
PS:肯定是要把服务器返回的http头跳过去,给m5httpdownnotifier传入接收的数据了<BR>
TBool ParseWebFileInfo(const TDesC8& recv_buf, TInt&
total_length, TInt& jump_len) ; </DIV>
<DIV> </DIV>
<DIV> //
内部函数用于从http的头获取相应的字段<BR> TBool GetRespField(const
TDesC8& recv_buf, TDesC8& field_name, TDesC8& end_flag,
TDes8& res) ; <BR> </DIV>
<DIV> //
下面这些就是常规的RSocket的操作了,初始化,发送请求,关闭连接<BR> TBool
InitSock(TDesC8& server_name, TInt server_port) ;
<BR> TBool SendReq(TDesC8& req_str) ;
<BR> TBool CloseSock() ; </DIV>
<DIV> </DIV>
<DIV>private:<BR> CM5HttpDown(M5HttpDownNotifier &
m5_notifier) ; <BR> void ConstructL() ; </DIV>
<DIV>public:<BR> // symbian标准的二段式构造,无需多言。</DIV>
<DIV> ~CM5HttpDown() ; <BR> static CM5HttpDown *
NewL(M5HttpDownNotifier& m5_notifier) ; <BR> static
CM5HttpDown * NewLC(M5HttpDownNotifier& m5_notifier) ; </DIV>
<DIV> </DIV>
<DIV> //
这两个是在下载过程中外部回调函数得到下载进度用的,例如文件的总的大小,现在已经下载的大小</DIV>
<DIV> TBool IsRunning() {return m_running ;
}<BR> TInt HttpTotalSize() { return
m_total_bytes ; }<BR> TInt HttpRecvSize() {
return m_recv_bytes ; } </DIV>
<DIV> </DIV>
<DIV> // 这里就是用来指定接入点的下载类型的了,是采用cmwap呢还是cmnet</DIV>
<DIV> // 正确的使用流程应该是先连接然后再下载</DIV>
<DIV> TBool HttpConnPorxy(TDesC8& uri, TInt down_type =
HTTP_DOWN_CMWAP) ; </DIV>
<DIV> </DIV>
<DIV> // 这个函数就是开始下载了<BR> TBool
HttpDown(TDesC8& uri, TInt recv_bytes = 0) ; <BR> TBool
HttpStopDown() ; <BR>} ; <BR>#endif</DIV>
<DIV> </DIV>
<DIV>下面就是M5HttpDown.cpp的关键内容了:</DIV>
<DIV>#include "m5httpdown.h"<BR>#include
<e32std.h><BR>#include <f32file.h></DIV>
<DIV> </DIV>
<DIV>// 移动的代理网关ip地址定义</DIV>
<DIV>_LIT(KCMCCWapProxy, "10.0.0.172") ; </DIV>
<DIV> </DIV>
<DIV>CM5HttpDown::CM5HttpDown(M5HttpDownNotifier &
m5_notifier):</DIV>
<DIV>m_m5_notifier(m5_notifier)<BR>{<BR> m_sock_eng = NULL ;
<BR>}</DIV>
<DIV> </DIV>
<DIV>CM5HttpDown::~CM5HttpDown()
<BR>{<BR> if(m_sock_eng->IsActive())
{<BR> m_sock_eng->Disconnect() ;
<BR> }<BR> delete m_sock_eng ; <BR>}</DIV>
<DIV> </DIV>
<DIV>void CM5HttpDown::ConstructL()<BR>{<BR> m_running = EFalse
;<BR> m_down_type = HTTP_DOWN_CMWAP ; <BR> m_is_first_resp
= ETrue ; <BR> m_total_bytes = 0 ; <BR> m_recv_bytes = 0
;<BR> m_web_port = HTTP_WEB_PORT ;
<BR> m_web_addr.SetLength(0) ;
<BR> m_web_fname.SetLength(0) ; <BR> m_sock_eng =
CSocketsEngine::NewL(*this) ;<BR>}</DIV>
<DIV> </DIV>
<DIV>CM5HttpDown * CM5HttpDown::NewL(M5HttpDownNotifier&
m5_notifier)<BR>{<BR> CM5HttpDown * self =
CM5HttpDown::NewLC(m5_notifier);<BR> CleanupStack::Pop(self);<BR> return
self;<BR>}</DIV>
<DIV> </DIV>
<DIV>CM5HttpDown * CM5HttpDown::NewLC(M5HttpDownNotifier&
m5_notifier)<BR>{<BR> CM5HttpDown * self = new (ELeave)
CM5HttpDown(m5_notifier);<BR> CleanupStack::PushL(self);<BR> self->ConstructL();<BR> return
self;<BR>}</DIV>
<DIV> </DIV>
<DIV>void CM5HttpDown::PrintNotify(const TDesC& aMessage, TUint
aAttributes)<BR>{<BR> m_m5_notifier.M5PrintNotify(aMessage) ;
<BR>}</DIV>
<DIV> </DIV>
<DIV>// 呵呵,这里通过检查在收到的数据中是否含有要下载的web地址来确定是否是移动的推送页面</DIV>
<DIV>// 一般来说,移动的推送页面都有一个你的地址,再加上一个&t=xxxxx这样的uri,所以可以</DIV>
<DIV>// 利用这一点来做到判别是否是推送页面</DIV>
<DIV>TBool CM5HttpDown::CheckRecv(const TDesC8&
recv_buf)<BR>{<BR> TInt find_pos ; <BR> find_pos =
recv_buf.Find(m_web_addr) ; <BR> if(find_pos != KErrNotFound)
return EFalse ; </DIV>
<DIV> return ETrue ; <BR>}</DIV>
<DIV> </DIV>
<DIV>void CM5HttpDown::RecvNotify(const TDesC8&
aMessage)<BR>{<BR> TInt recv_bytes = aMessage.Length() ;
<BR> TInt jump_length = 0 ; <BR> <BR> if(recv_bytes
> 0) {</DIV>
<DIV> </DIV>
<DIV> //
如果是第一次收到的话,就需要判断是否是推送页面<BR> if(m_is_first_resp)
{<BR> if(CheckRecv(aMessage)) {<BR></DIV>
<DIV> // 如果不是推送页面,则把文件的总共大小读取出来</DIV>
<DIV> if(ParseWebFileInfo(aMessage,
m_total_bytes, jump_length)) {</DIV>
<DIV> </DIV>
<DIV> //
第一次接收数据,m_recv_bytes理论上应该等于0;如果不等于0则代表本次下载是</DIV>
<DIV> //
断点续传,需要把这个m_recv_bytes已经下载的字节数加入到m_total_bytes里面去。<BR> if(m_recv_bytes
> 0) <BR> m_total_bytes +=
m_recv_bytes ; </DIV>
<DIV> </DIV>
<DIV>
// 肯定了,实际收到的字节数是需要跳过http头的,所以这里引入了jump_length<BR> m_recv_bytes
+= (recv_bytes - jump_length) ; </DIV>
<DIV> </DIV>
<DIV> // 一切准备妥当,然后调用M5RecvNotify函数来告知收到了数据<BR> m_m5_notifier.M5RecvNotify(aMessage.Mid(jump_length))
; <BR> }</DIV>
<DIV> </DIV>
<DIV> //
既然第一次已经收到数据了,接下来的数据就是源源不断的到来了,就不必每次都跟第一次接收到</DIV>
<DIV> // 数据还需要解析什么http这么麻烦了,直接收到,然后调用recv
notify即可。<BR> m_is_first_resp = false ;
<BR> } else {</DIV>
<DIV> // 这里输出check
failed的时候,意味着收到了移动的推送页面,需要重发一遍下载的request才行<BR> TBuf<20>
s ; <BR> s.Format(_L("check failed !")) ;
<BR> PrintNotify(s) ;
<BR> }<BR> } else
{<BR> // common receive procdure </DIV>
<DIV> //
这里就是直接接收数据,然后存盘了<BR> if((m_recv_bytes + recv_bytes)
> m_total_bytes) {<BR> recv_bytes =
m_total_bytes - m_recv_bytes ;
<BR> m_recv_bytes = m_total_bytes ;
<BR> } else
{<BR> m_recv_bytes += recv_bytes
;
<BR> }<BR> m_m5_notifier.M5RecvNotify(aMessage)
; <BR> }<BR> }<BR>}</DIV>
<DIV> </DIV>
<DIV>void CM5HttpDown::ErrorNotify(const TDesC& aErrMessage,
TInt aErrCode)
<BR>{<BR> m_m5_notifier.M5PrintNotify(aErrMessage) ;
<BR>}</DIV>
<DIV> </DIV>
<DIV>void CM5HttpDown::SetStatus(const TDesC&
aStatus)<BR>{<BR> m_m5_notifier.M5PrintNotify(aStatus) ;
<BR>}</DIV>
<DIV> </DIV>
<DIV>TBool CM5HttpDown::SendReq(TDesC8& req_str) <BR>{<BR>
if(m_sock_eng->Connected()) {<BR>
m_sock_eng->WriteL(req_str) ; <BR> return ETrue
; <BR> }<BR> return EFalse ; <BR>}</DIV>
<DIV> </DIV>
<DIV>// 这个函数看上去很让人恼火,没办法symbian的字符串描述符就是这个样子的。</DIV>
<DIV>TBool CM5HttpDown::ParseUri(TDesC8& uri, TDes8&
web_addr, TDes8& web_fname, TInt&
web_port)<BR>{<BR> TPtrC8 uri_ptr ;
<BR> TBuf8<30> tmp_buf ;
<BR> TInt find_pos = 0 ; </DIV>
<DIV> web_port = HTTP_WEB_PORT ;
<BR> if(uri.Length() <= 0) return false ;</DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -