1. 程式人生 > >c++HTTP方式傳輸檔案流備忘

c++HTTP方式傳輸檔案流備忘

轉載自哪裡忘記了,但是肯定是csdk一個問題中的回帖。暫時備忘

time_t tNow = time(0);
 char strBoundary[256] = {0};
 tm tmNow = *localtime(&tNow);
 long lTimeTick = GetTickCount();

//boundary欄位,區分檔案正文和結尾的特殊標誌。每當用刀這個欄位的時候,前面必須加--
 _snprintf(strBoundary,256,"%s%d%d%d%d%d%d%d",BOUNDARY_FILE_OCX,
   tmNow.tm_year+1900,tmNow.tm_mon+1,tmNow.tm_mday,tmNow.tm_hour,tmNow.tm_min,tmNow.tm_sec,lTimeTick);
#if IS_USE_WININET
        BOOL bRet = FALSE;
        CString strServer, strObject, strHeader, strRet;
        unsigned short nPort;
        DWORD dwServiceType;
  
  char sLocalFileName[256] = {0};
  _snprintf(sLocalFileName,256,"%s",sLocalFilePath);
  int nFilePathLen = strlen(sLocalFilePath);
  int nFileIndex = 0;
  while (nFilePathLen)
  {
   char s = sLocalFilePath[nFilePathLen];
   if (s == '/' || s == '\\')
   {
    break;
   }
   nFilePathLen--;
  }
  

  CString strName;
  strName.Format("%s",sLocalFilePath);
  strName = strName.Right(strName.GetLength() - nFilePathLen - 1);

  //檔案開始頭,攜帶一些http檔案伺服器所需要的一些資料,格式不定。
  char cont_desc[1024];
  sprintf(cont_desc, "--%s\r\nContent-Disposition: form-data; name=\"Filename\"\r\n\r\n%s\r\n"
   "--%s\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n%s\r\n"
   "--%s\r\nContent-Disposition: form-data; name=\"userName\"\r\n\r\n%s\r\n"
   "--%s\r\nContent-Disposition: form-data; name=\"file\";filename=\"%s\"\r\n"
   "Content-Type: application/octet-stream\r\n\r\n",
   strBoundary,strName.GetBuffer(0),
   strBoundary,strName.GetBuffer(0),
   strBoundary,sUserName,
  strBoundary,strName.GetBuffer(0));

  char boundary_end[1024] = {0};   
  sprintf(boundary_end, "\r\n--%s--\r\n",
  strBoundary);
  
  int fd;
  int file_size = 0;
  int data_size = 0;
  int res;
  char *file_buf = NULL;
  struct stat statBuf;
  // get the size of file
  if(stat(sLocalFilePath, &statBuf) < 0)
  {
   fprintf(stderr, "stat error!\n");
   return NULL;
  }
  file_size = statBuf.st_size;
  
  file_buf = (char*)malloc(file_size);
  if(file_buf == NULL)
  {
   fprintf(stderr, "malloc error!\n");
   return NULL;
  }
  //open & read to the buffer
  fd = open(sLocalFilePath, O_RDONLY, 0);
  if(fd < 0)
  {
   fprintf(stderr, "open error!\n");
   if (file_buf)
   {
    delete file_buf;
    file_buf = NULL;
   }

   return NULL;
  }
  
  res = read(fd, file_buf, file_size);
  if(res < 0)
  {
   fprintf(stderr, "read error!\n");
   
   if (file_buf)
   {
    delete file_buf;
    file_buf = NULL;
   }

   close(fd);
   return NULL;
  }
   //檢測輸入網址是否正確,病提取ip,埠,和傳輸地址。

        if(!AfxParseURL(sHttpServer, dwServiceType, strServer, strObject, nPort))
        {
   if (file_buf)
   {
    delete file_buf;
    file_buf = NULL;
   }
   close(fd);
            return sReturn;
        }
        CInternetSession sess;//Create session
 
        CHttpFile* pFile;
        //////////////////////////////////////////////
        CHttpConnection *pServer = sess.GetHttpConnection(strServer, nPort); 
        if(pServer == NULL)
        {
   if (file_buf)
   {
    delete file_buf;
    file_buf = NULL;
   }
   close(fd);
            return sReturn;
        }

//上傳地址sObgect,根據伺服器需要可能需要
  char sObgect[256] = {0};
  _snprintf(sObgect,256,"%s%s",strObject,strObject);

        pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST,sObgect,NULL,1,NULL,NULL,INTERNET_FLAG_EXISTING_CONNECT); 
        if(pFile == NULL)
        {
   if (file_buf)
   {
    delete file_buf;
    file_buf = NULL;
   }
   close(fd);
            return sReturn;
        }
  char strTmp[256] = {0};

//檔案流傳輸必須使用此種方式

  _snprintf(strTmp,256,"Content-Type: multipart/form-data;charset=utf-8; boundary=%s\r\n",strBoundary);
        bRet = pFile -> AddRequestHeaders(strTmp); 
        bRet = pFile -> AddRequestHeaders("Accept: */*");
  _snprintf(strTmp,256,"Host:%s:%d",strServer,nPort);
  bRet = pFile->AddRequestHeaders(strTmp);
  bRet = pFile->AddRequestHeaders("Connection: Keep-Alive\r\n");
  bRet = pFile->AddRequestHeaders("Cache-Control: no-cache\r\n\r\n");


  //傳送資料
  int nAllLen = strlen(cont_desc)+file_size+strlen(boundary_end);
  char *sAllBuf = new char[nAllLen+1];
  memset(sAllBuf,0,nAllLen+1);
  int nOffSet = 0;
  //拷貝資料頭
  memcpy(sAllBuf+nOffSet,cont_desc,strlen(cont_desc));
  nOffSet = strlen(cont_desc);
  //拷貝檔案資料
  memcpy(sAllBuf+nOffSet,file_buf,file_size);
  nOffSet = strlen(cont_desc)+file_size;
  //拷貝檔案結束符
  memcpy(sAllBuf+nOffSet,boundary_end,strlen(boundary_end));
  //一次性將 資料頭,檔案資料和檔案結束符傳送過去。

//防止出現單獨傳送的時候伺服器卡掉或者這邊卡掉導致資料傳送不完全的現象。
  bRet = pFile->SendRequest(NULL,0,sAllBuf,nAllLen);
 //讀取伺服器返回資料。
        CString strSentence;
        DWORD dwStatus;
        DWORD dwBuffLen = sizeof(dwStatus);
        BOOL bSuccess = pFile->QueryInfo(
            HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
            &dwStatus, &dwBuffLen);
 
        if( bSuccess && dwStatus>=  200 && dwStatus<300) 
        {
            char buffer[2049];
            memset(buffer, 0, 2049);
            int nReadCount = 0;
            while((nReadCount = pFile->Read(buffer, 2048)) > 0)
            {
                strSentence += buffer;
                memset(buffer, 0, 2049);
            }
            bRet = true;
        }
        else
        {
            bRet = false;
        }
  
  if (file_buf)
  {
   delete file_buf;
   file_buf = NULL;
  }
  if (sAllBuf)
  {
   delete sAllBuf;
   sAllBuf = NULL;
  }
  close(fd);
        ////////////////////////////////////////
        pFile->Close();
        sess.Close();
  sReturn = new char[strSentence.GetLength()+1];
  _snprintf(sReturn,strSentence.GetLength(),"%s",strSentence.GetBuffer(0));
        return sReturn;