多文件断点续传组件(MFC ActiveX)

多文件断点续传组件(MFC ActiveX)是一个用于Web上传文件的ActiveX控件,他应该支持断点和多文件异步上传。

针对断点续传组件,我需要解决下面5个问题:

 

1、 文件状态问题

2、 文件传输效率与安全问题

3、 编码问题

4、 系统设计问题

5、 交互问题

 

 

一、文件状态问题

一个文件从被打开到关闭,它需要经过4种状态:初始化、就绪、上传中、完成,而且他们仅有一种转化关系(初始化→就绪→上传中→完成)。实际上,为了实现断点续传,我还需要引进两种状态:等待和暂停。

 


1

考虑到组件的健壮性,还需要一个“出错”状态来容错(见图1),如上传超时的时候。

状态结构

 

enum FileStates{

         State_Init = 0,

         State_Pending = 1,

         State_Uploading = 2,

         State_Waiting = 3,

         State_Paused = 4,

         State_Finished = 5,

         State_Error = 6       

};

 

 

二、文件传输效率与安全问题

我们知道,大多数Web服务器出于安全考虑,会限制一次请求上传数据量,比如ASP.NET,默认的文件大小上限为4MB,是为了避免潜在DOS攻击危险。若是攻击者提交了一个或多个大文件,往往会让服务器不堪重负。若是用户上传的文件大于4MB,将会得到“Maximum request length exceeded.”异常信息。当然,我们可以更改默认设置,但是,这样将是以安全为代价去换回文件的上限。我们可以考虑将一个文件分割成多次请求发送,这样做的后果是出现了新的问题——传输效率问题。

假设有一个fKB的文件需要上传,当前网络传输速率vKB/s,每次请求响应时间ts

文件大小没有上限情况:


表示完成上传所需要的时间。

文件大小上限为MKB的情况:





分析可知,当f<M时,由于每次请求都要消耗(n+1)t时间,所以大文件分次传输要比一次传输多耗时,一个常量级的增长是可以接受的。

 

三、编码问题

 

从组件向服务器发送的数据要符合规范URL的标准,但是服务器对于规范URL的标准德解释是没有规定的,这样我们向服务器发送数据还存在编码不一致性的问题。通常浏览器会用两种编码方式发送URL到服务器,分别是UTF-8和ANSI(当前系统语言设置,在Windows系统中可以理解为当前代码页)。

3.1、直接在地址栏输入URL的情况

中文Windows环境下,假如直接在浏览器的地址栏输入URL:

http://www.charset.cn/中国.html?kw=中国

  1. IE浏览器特性

 

PATH部分

参数部分

UTF-8模式(默认)

%E4%B8%AD%E5%9B%BD.html

kw=中国

 

UTF-8编码、urlencode

GBK编码、无urlencode

ANSI模式

中国.html

kw=中国

 

GBK编码、无urlencode

GBK编码、无urlencode

  1. 中文Windows环境下,IE中默认发送的URL的PATH部分是UTF-8编码,参数部分是GBK编码。IE的设置选项中有一项是“总是以 UTF-8 发送URL”可以改变发送URL的编码为ANSI。
  2. FireFox浏览器特性

 

PATH部分

参数部分

UTF-8模式

%E4%B8%AD%E5%9B%BD.html

kw=%E4%B8%AD%E5%9B%BD

 

UTF-8编码、urlencode

UTF-8编码、urlencode

ANSI模式(默认)

%D6%D0%B9%FA.html

kw=%D6%D0%B9%FA

 

GBK编码、urlencode

GBK编码、urlencode

  1. 中文Windows环境下FireFox中默认发送的URL的PATH和参数都是GBK编码,在FireFox地址栏输入“about:config”,找到选项“network.standard-url.encode-utf8”,即可改变发送URL的编码方式。
  2. Opera浏览器特性

 

PATH部分

参数部分

UTF-8模式(默认)

%E4%B8%AD%E5%9B%BD.html

kw=%E4%B8%AD%E5%9B%BD

 

UTF-8编码、urlencode

UTF-8编码、urlencode

3.2、来自网页中的链接

在不同的浏览器中打开不同编码的网页中的链接,特性也不相同。在不改变浏览器默认选项情况下访问不同编码的网页中以下链接:

http://www.charset.cn/中国.html?kw=中国

  1. IE浏览器特性

 

PATH部分

参数部分

UTF-8网页

%E4%B8%AD%E5%9B%BD.html

kw=中国

 

UTF-8编码、urlencode

UTF-8编码、无urlencode

GBK网页

%E4%B8%AD%E5%9B%BD.html

kw=中国

 

UTF-8编码、urlencode

GBK编码、无urlencode

  1. FireFox浏览器特性

 

PATH部分

参数部分

UTF-8网页

%E4%B8%AD%E5%9B%BD.html

kw=%E4%B8%AD%E5%9B%BD

 

UTF-8编码、urlencode

UTF-8编码、urlencode

GBK网页

%D6%D0%B9%FA.html

kw=%D6%D0%B9%FA

 

GBK编码、urlencode

GBK编码、urlencode

对此,我们需要在组件中实现URL编码。

 

编码实现

CString CURLEncode::UrlEncodeUtf(CString strUnicode)

{

         USES_CONVERSION;

         LPCWSTR unicode = T2CW(strUnicode);

         int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0);

         if (!len)

                   return strUnicode;

         char *utf8 = new char[len + 1];

         char *utf8temp = utf8;

         WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len + 1, 0, 0);

         utf8[len] = NULL;  

         CString strTemp, strEncodeData;

         while (*utf8 != '\0')

         {

                   strTemp.Format(_T("%%%2x"), (BYTE)*utf8);

                   strEncodeData += strTemp;

                   ++utf8;

         }

 

         delete []utf8temp;

 

         return CString(strEncodeData);

 

}

 

 

CString CURLEncode::Utf8ToStringT(LPSTR str)

{

         _ASSERT(str);

         USES_CONVERSION;

         WCHAR *buf;

         int length = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);

         buf = new WCHAR[length+1];

         ZeroMemory(buf, (length+1) * sizeof(WCHAR));

         MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, length);

        

         return (CString(W2T(buf)));

}

 

CString CURLEncode::UrlDecodeUtf(CString UtfUrl)

{

         _ASSERT(UtfUrl);

         USES_CONVERSION;

         LPSTR _url = T2A(const_cast<LPTSTR>(UtfUrl.GetBuffer(UtfUrl.GetLength())));

         int i = 0;

         int length = (int)strlen(_url);

         CHAR *buf = new CHAR[length];

         ZeroMemory(buf, length);

         LPSTR p = buf;

         while(i < length)

         {

                   if(i <= length -3 && _url[i] == '%' && IsHexNum(_url[i+1]) && IsHexNum(_url[i+2]))

                   {

                            sscanf(_url + i + 1, "%x", p++);

                            i += 3;

                   }

                   else

                   {

                            *(p++) = _url[i++];

                   }

         }

         return Utf8ToStringT(buf);

}

posted @ 2010-01-09 16:08  Yibu  阅读(1754)  评论(0编辑  收藏  举报