您的位置:首页 > 其它

(转)使用MFC的WinINet库来实现图片文件的上传

2010-10-21 21:36 501 查看
VC++用来进行Internet客户端编程的基础知识的介绍,主要见这个网址:

http://msplinks.com.cn/MDFodHRwOi8vd3d3LnZja2Jhc2UuY29tL2RvY3VtZW50L3ZpZXdkb2MvP2lkPTU0NQ==

微软的官网给出了一个使用HttpSendRequestEx函数进行大文件上传的实例,并给出了hsrex.ex文件即是这个例子的压缩包。这个例子的详细的介绍以及hsrex.exe文件的使用见网址:

http://msplinks.com.cn/MDFodHRwOi8vc3VwcG9ydC5taWNyb3NvZnQuY29tL2tiLzE3NzE4OC9FTi1VUy8=

Article ID: 177188

中文版的:http://support.microsoft.com/kb/177188

又查找到了一些别人用VC实现http上传文件的例子,可以参考一下,但是都存在问题,需要解决:

http://msplinks.com.cn/MDFodHRwOi8vdG9waWMuY3Nkbi5uZXQvdC8yMDA1MTExNi8xMC80Mzk2MzgyLmh0bWw=#

http://msplinks.com.cn/MDFodHRwOi8vd3d3Lnphb3h1ZS5jb20vYXJ0aWNsZS90ZWNoLTczMTQ1Lmh0bQ==
http://chrisqiqi1984.spaces.live.com/blog/cns!6A9BDC7776B254BC!106.entry


又找到了几个有帮助的网页:
http://topic.csdn.net/u/20080514/12/dec0df69-3536-48d0-b952-1a81af577f42.html http://blog.csdn.net/shengang1978/archive/2008/11/13/3291398.aspx http://topic.csdn.net/t/20050321/11/3867461.html http://www.codeproject.com/KB/IP/simplehttpclient.aspx




由于项目的临时需求,需要将以前抓拍在本机的BMP图片上传至服务器。本文主要记录如何解决这个问题。

我们打算用http协议来上传数据,因此要用http协议的POST方式。首先,要理解http的POST协议。它一般由三部分组成:协议头,具体内容以及协议尾。如下例所示:

POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive

-----------------------------7d33a816d302b6
Content-Disposition: form-data; name="userfile1"; filename="E:/s"
Content-Type: application/octet-stream

a
bb
XXX
ccc
-----------------------------7d33a816d302b6
Content-Disposition: form-data; name="text1"

foo
-----------------------------7d33a816d302b6
Content-Disposition: form-data; name="password1"

bar
-----------------------------7d33a816d302b6--



实例的红色字体部分就是协议的头。给服务器上传数据时,并非协议头每个字段都得说明,其中,content-type是必须的,它包括一个类似标志性质的名为boundary的标志,它可以是随便输入的字符串。对后面的具体内容也是必须的。它用来分辨一段内容的开始。绿色字体部分就是需要上传的数据,可以是文本,也可以是图片等。数据内容前面需要有Content-Disposition, Content-Type以及Content-Transfer-Encoding等说明字段。最后的紫色部分就是协议的结尾了。

下面给出关键的VC实现代码及相关说明:

首先,根据HTTP的POST协议,封装协议头。

// strBoundary 为协议中的boundary

CString MakeRequestHeaders(CString &strBoundary)
{
CString strFormat=_T("");
CString strData =_T("");
strFormat += _T("Content-Type: multipart/form-data; boundary=%s/r/n");
strFormat +=_T("Host: %s:%d/r/n");
strData.Format(strFormat, strBoundary,m_strSeverName, m_nPort);

return strData;
}

其次,封装数据前面的描述部分:

CString MakePreFileData(CString &strBoundary, CString &strFileName)
{
//Content-Type:
//JPG image/pjpeg
//PNG image/x-png
//BMP image/bmp
//TIF image/tiff
//GIF image/gif
CString strFormat=_T("");
CString strData=_T("");
strFormat += _T("--%s");
strFormat += _T("/r/n");
strFormat += _T("Content-Disposition: form-data; name=/"filedata/"; filename=/"%s/"");
strFormat += _T("/r/n");
strFormat += _T("Content-Type: image/bmp");
strFormat += _T("/r/n");
strFormat += _T("Content-Transfer-Encoding: binary");
strFormat += _T("/r/n/r/n");

strData.Format(strFormat, strBoundary, strFileName);

return strData;
}

第三,封装协议尾。

CString MakePostFileData(CString &strBoundary)
{
CString strFormat;
CString strData;

strFormat = _T("/r/n");
strFormat += _T("--%s");
strFormat += _T("/r/n");
strFormat += _T("Content-Disposition: form-data; name=/"submitted/"");
strFormat += _T("/r/n/r/n");
strFormat += _T("submit");
strFormat += _T("/r/n");
strFormat += _T("--%s--");
strFormat += _T("/r/n");

strData.Format(strFormat, strBoundary, strBoundary);

return strData;
}

经过上面这些工作,http协议这部分工作差不多完成了,需要注意的是传输文件时,form-data中的name字段要和服务器中的名字一致。

既然协议已经封装好了,那么接下来就要解决与服务器的连接工作了,在VC中,可以使用类CInternetSession来创建并初始化一个简单的Internet对话。首先,在应用程序中,建立一个CIternetSession类对象,然后,利用GetHttpConnection函数来建立一个HTTP连接并且它返回一个CHttpConnection对象的指针。其次,再利用OpenRequest方法来打开一个HTTP连接,接着可以用AddRequestHeaders方法来添加一个或多个HTTP请求的头,即HTTP协议头。然后再利用SendRequestEx发送一个请求至HTTP服务器,同时,利用该函数,加上CInternetFile的方法Write和WriterString可以发送各种类型的数据至服务器,但我们必需知道整个文件的大小=协议头大小+数据描述字段字节大小+实际数据字节大小+协议尾大小。当发送完数据后,需用EndRequest方法来关闭连接。具体代码如下:

BOOL SendTrack()
{
int startp = m_strFilePath.ReverseFind('//');
int namelen = m_strFilePath.GetLength()-startp-1;

CString strFileName = m_strFilePath.Mid(startp+1,namelen);

UpdateData(TRUE);
CString defServerName =m_strSeverName;
CString defObjectName =m_strObject;
// USES_CONVERSION;
CInternetSession Session;
CHttpConnection *pHttpConnection = NULL;
INTERNET_PORT nPort = m_nPort;
CFile fTrack;
CHttpFile* pHTTP;
CString strRequestHeader=_T("");
CString strHTTPBoundary=_T("");
CString strPreFileData=_T("");
CString strPostFileData=_T("");
CString strResponse =_T("");
DWORD dwTotalRequestLength;
DWORD dwChunkLength;
DWORD dwReadLength;
DWORD dwResponseLength;
TCHAR szError[MAX_PATH];
void* pBuffer =NULL;
LPSTR szResponse;

BOOL bSuccess = TRUE;

CString strDebugMessage =_T("");

if (FALSE == fTrack.Open(m_strFilePath, CFile::modeRead | CFile::shareDenyWrite))
{
AfxMessageBox(_T("Unable to open the file."));
return FALSE;
}

strHTTPBoundary = _T("-----------------------------7d86d16250370");
strRequestHeader =MakeRequestHeaders(strHTTPBoundary);
strPreFileData = MakePreFileData(strHTTPBoundary, strFileName);
strPostFileData = MakePostBmpFileData(strHTTPBoundary);

MessageBox(strRequestHeader,"RequestHeader",MB_OK | MB_ICONINFORMATION);
MessageBox(strPreFileData,"PreFileData",MB_OK | MB_ICONINFORMATION);
MessageBox(strPostFileData,"PostFileData",MB_OK | MB_ICONINFORMATION);

dwTotalRequestLength = strPreFileData.GetLength() + strPostFileData.GetLength() + fTrack.GetLength();

dwChunkLength = 64 * 1024;

pBuffer = malloc(dwChunkLength);

if (NULL == pBuffer)
{
return FALSE;
}

try
{
pHttpConnection = Session.GetHttpConnection(defServerName,nPort);
pHTTP = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, defObjectName);
pHTTP->AddRequestHeaders(strRequestHeader);
pHTTP->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE);

#ifdef _UNICODE
pHTTP->Write(W2A(strPreFileData), strPreFileData.GetLength());
#else
pHTTP->Write((LPSTR)(LPCSTR)strPreFileData, strPreFileData.GetLength());
#endif

dwReadLength = -1;
while (0 != dwReadLength)
{
strDebugMessage.Format(_T("%u / %u/n"), fTrack.GetPosition(), fTrack.GetLength());
TRACE(strDebugMessage);
dwReadLength = fTrack.Read(pBuffer, dwChunkLength);
if (0 != dwReadLength)
{
pHTTP->Write(pBuffer, dwReadLength);
}
}

#ifdef _UNICODE
pHTTP->Write(W2A(strPostFileData), strPostFileData.GetLength());
#else
pHTTP->Write((LPSTR)(LPCSTR)strPostFileData, strPostFileData.GetLength());
#endif

pHTTP->EndRequest(HSR_SYNC);

dwResponseLength = pHTTP->GetLength();
while (0 != dwResponseLength)
{
szResponse = (LPSTR)malloc(dwResponseLength + 1);
szResponse[dwResponseLength] = '/0';
pHTTP->Read(szResponse, dwResponseLength);
strResponse += szResponse;
free(szResponse);
dwResponseLength = pHTTP->GetLength();
}
MessageBox(strResponse,"Response",MB_OK | MB_ICONINFORMATION);
}
catch (CException* e)
{
e->GetErrorMessage(szError, MAX_PATH);
e->Delete();
AfxMessageBox(szError);
bSuccess = FALSE;
}
pHTTP->Close();
delete pHTTP;

fTrack.Close();

if (NULL != pBuffer)
{
free(pBuffer);
}
return bSuccess;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: