使用MFC的WinINet庫來實現圖片檔案的上傳

來源:互聯網
上載者:User

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;
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.