• 转:通过HTTP协议利用VC++上传图片至服务器


    文章来自:http://blog.myspace.cn/e/403946587.htm

    通过HTTP协议利用VC++上传图片至服务器

    由于项目的临时需求,需要将以前抓拍在本机的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;
    }

     

     

  • 相关阅读:
    八 sizeof枚举
    九 推算程序结果
    十 交换变量特殊写法
    十一 移位-加减优先级 define undef
    十二 部分易忽略的优先级优先级
    十三 C语言的#特殊用法
    十四 访问数组:指针形式,下标形式
    VS出现未加载wntdll.pdb的解决办法
    C++继承产生的问题
    opencv加载图片imread失败的原因
  • 原文地址:https://www.cnblogs.com/cumtb3S/p/1747499.html
Copyright © 2020-2023  润新知