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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: VC是指Visual C++,而http协议是一种用于传输超文本的协议。在VC中使用http协议下载文件可以通过以下步骤实现。 首先,需要使用VC提供的网络编程库,如WinINet或WinHTTP。这些库提供了一些函数和类,用于与服务器进行http通信。 其次,需要创建一个http会话并与服务器建立连接。这可以通过调用相关函数来实现,如InternetOpen、InternetConnect等。 然后,要使用http协议发送下载文件的请求。可以使用HTTP GET方法向服务器发送请求,并指定要下载的文件的URL。这可以通过调用相关函数,如HttpOpenRequest、HttpSendRequest等来实现。 接下来,需要接收服务器的响应并获取待下载文件的信息,如文件大小、文件类型等。可以使用相关函数如HttpQueryInfo等来实现。 然后,创建本地文件并准备接收服务器发送的文件内容。可以使用相关函数如CreateFile、WriteFile等来实现。 最后,从服务器接收文件内容并将其写入本地文件中。这可以通过调用相关函数如InternetReadFile等来实现,直到接收完整个文件。 需要注意的是,在下载过程中需要严密地处理各种可能的错误和异常情况,以确保下载过程的稳定性和可靠性。 以上是使用VC中http协议下载文件的大致步骤,具体的实现细节可以根据具体情况和需求进行调整和完善。 ### 回答2: VC(Virtual Channel)是在计算机网络中用于传输数据的通道,它是一种在网络服务器和客户端之间建立连接并传输数据的协议。HTTP(Hypertext Transfer Protocol)是一种用于在网络上传输超文本的协议。 在使用VC协议下载文件时,通常会结合HTTP协议来完成文件的传输。具体的步骤如下: 1. 客户端向服务器发送HTTP请求,请求下载文件的URL。 2. 服务器接收到请求后,通过VC协议建立与客户端的连接,并开始传输文件。 3. 服务器根据请求的URL找到对应的文件,并以HTTP响应的形式返回给客户端。 4. 客户端接收到服务器的响应后,开始通过VC协议接收文件数据。 5. 服务器通过VC协议将文件数据分包发送给客户端,客户端通过接收这些包来获取完整的文件数据。 6. 当服务器传输完整个文件后,关闭与客户端的连接。 通过以上步骤,客户端就能够使用VC协议下载HTTP协议中请求的文件。VC协议通过在网络上建立可靠的连接来确保数据的完整性和准确性。而HTTP协议则负责处理客户端和服务器之间的通信,并提供对文件的请求和响应。 总结起来,通过VC和HTTP协议的结合,实现了在网络上下载文件的功能,使得文件的传输更加可靠和高效。 ### 回答3: VC是Visual C++的简称,是一种面向对象的编程语言。VC可以使用HTTP协议下载文件,以下是下载文件的步骤: 1. 创建一个Win32控制台应用程序的工程,打开VC开发环境。 2. 在代码中引入必要的头文件,如 <winhttp.h> 和 <iostream>。 3. 使用WinHTTP库进行HTTP请求,可以使用WinHttpOpen函数初始化HTTP会话,然后使用WinHttpOpenRequest函数创建HTTP请求。 4. 设置HTTP请求的参数,包括请求的method(GET或POST),URL、头部信息等。 5. 发送HTTP请求,使用WinHttpSendRequest函数发送请求到服务器。 6. 接收HTTP响应,使用WinHttpReceiveResponse函数接收服务器的响应。 7. 判断响应状态,使用WinHttpQueryHeaders函数查询响应头部信息,判断请求是否成功。 8. 创建本地文件,使用CreateFile函数创建保存文件的本地文件。 9. 读取响应数据,使用WinHttpReadData函数持续读取服务器返回的数据,并写入本地文件。 10. 关闭HTTP请求和会话,使用WinHttpCloseHandle函数关闭请求和会话句柄。 11. 关闭本地文件,使用CloseHandle函数关闭本地文件句柄。 以上是使用VC编写的HTTP协议下载文件的基本过程。在实际应用中,还可以添加错误处理、进度显示等功能,以提高用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值