C++实现HTTP上传

2023-05-16

 插件中需要一个上传文件的功能,我跟老大说,我想FTP上传,老大一瞪眼,那还得再布个FTP服务器,直接用HTTP上传多简单。
        那么C++如何将文件上传HTTP服务器上呢? 

HTTP上传

       HTTP上传文件的时候,需要设置Content-Type为multipart/form-data;它包括一个类似标志性质的名为boundary的标志,它可以是随便输入的字符串。如boundary=----fasjdflkj23r8uffsdl, 对后面的具体内容也是必须的。它用来分辨一段内容的开始,用于将后面的数据分成数据块数据可以文本,也可以是文件等。数据内容前面需要有Content-Disposition, Content-Type以及Content-Transfer-Encoding等说明字段。最后结束加入结束标记。

       下面是一个发送给服务器的数据内容示例:

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="password1"

 

bar

-----------------------------7d33a816d302b6—

Content-Dispostion:form-data; name="submitted"

 

Submit

-----------------------------7d33a816d302b6—

 

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

 

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

 

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

 

// strBoundary 为协议中的boundary


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


第三,封装协议尾


注意,其中的\r\n换行必不可少,否则会报错。

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

 

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

BOOL SendTrack(CString strURL,CString m_strFilePath)
{
    int startp = m_strFilePath.ReverseFind('\\');
    int namelen = m_strFilePath.GetLength()-startp-1;
       
       CString strFileName = m_strFilePath.Mid(startp+1,namelen);
       
       //UpdateData(TRUE);
       BOOL bResult = FALSE;
       DWORD dwType = 0;
       CString strServer;
       CString strObject;
       INTERNET_PORT wPort = 0;
 
       bResult =  AfxParseURL(strURL, dwType, strServer, strObject, wPort);
 
       CString defServerName =strServer;
       CString defObjectName =strObject; 
       // USES_CONVERSION;
       CInternetSession Session;
       CHttpConnection *pHttpConnection = NULL;
       INTERNET_PORT   nPort = wPort;
       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,strServer,wPort);
       strPreFileData = MakePreFileData(strHTTPBoundary, strFileName);
       strPostFileData = MakeRequestEnders(strHTTPBoundary);
       
       MessageBox(NULL,strRequestHeader,"RequestHeader",MB_OK | MB_ICONINFORMATION); 
       MessageBox(NULL,strPreFileData,"PreFileData",MB_OK | MB_ICONINFORMATION);
       MessageBox(NULL,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(NULL,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;
}

我测试将文件上传到java服务器上,由自己写的severlet上,后来使用sturts2,发现上传文件的目录会被sturts2去掉,还有就是C++提交的参数中不能使用中文,试过各种转,但没一种好用,但是java返回参数却没有问题。C++编码转java不知道如何转,其他一切正常。




 下面我测试用的JAVA代码

 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
public class ImgAction extends ActionSupport implements Preparable {
    /**
     * 
     */
    private static final long serialVersionUID = -6351719999821998719L;
    protected HttpSession session;
    protected HttpServletRequest request;
    protected ActionContext context;
    protected HttpServletResponse response;
    // 上传文件
    private File upload;
    private String uploadFileName;
    private String uploadContentType;
    
    
    /**
     * @return the upload
     */
    public File getUpload() {
        return upload;
    }
    /**
     * @param upload the upload to set
     */
    public void setUpload(File upload) {
        this.upload = upload;
    }
 
    /**
     * @return the uploadFileType
     */
    /**
     * @return the uploadFileName
     */
    public String getUploadFileName() {
        return uploadFileName;
    }
    /**
     * @return the uploadContentType
     */
    public String getUploadContentType() {
        return uploadContentType;
    }
    /**
     * @param uploadContentType the uploadContentType to set
     */
    public void setUploadContentType(String uploadContentType) {
        this.uploadContentType = uploadContentType;
    }
    /**
     * @param uploadFileName the uploadFileName to set
     */
    public void setUploadFileName(String uploadFileName) {
        this.uploadFileName = uploadFileName;
    }
    /**
     * 初始化session和request变量
     */
    public void prepare() throws Exception {
        context = ActionContext.getContext();
        request = ServletActionContext.getRequest();
        session = request.getSession();
        response = ServletActionContext.getResponse();
    }
    // 图片根目录
    private static final String BASEPATH = "C:/upload/";
    
    public String toImg() {
        String m = request.getParameter("m");
        List<String> fileType = Arrays.asList(new String[] { "jpg", "png",
                "bmp", "gif", "tif" }); // 上传的文件类型
        List<String> list = new ArrayList<String>();
        // 获取文件目录
        File file = new File(BASEPATH);
        
        if(file.isDirectory()){
            // 获取目录下文件列表
            File[] files = file.listFiles();
    
            for (int i = 0; i < files.length; i++) {
                if (!files[i].isDirectory()) {
                    String picPath = files[i].toString();
                    String wjlx = picPath.substring(picPath.indexOf(".") + 1,
                            picPath.length()).toLowerCase();
                    if (fileType.contains(wjlx)) {
                        list.add(picPath.substring(picPath.lastIndexOf('\\') + 1));
                    }
                }
            }
            this.request.setAttribute("picPath", list);
        }
        
        if (m.equals("1")) {
            return "m1";
        } else {
            return "m2";
        }
    }
    /**
     * 显示图片
     */
    public void showImg() {
        String name = request.getParameter("filename");
        OutputStream toClient = null;
        try {
            // 以byte流的方式打开文件
            FileInputStream hFile = new FileInputStream(BASEPATH + name);
            // 得到文件大小
            int i = hFile.available();
            byte data[] = new byte[i];
            hFile.read(data); // 读数据
            hFile.close();
            // 设置返回的文件类型
            response.setContentType("image/*");
            // 得到向客户端输出二进制数据的对象
            toClient = response.getOutputStream();
            // 输出数据
            toClient.write(data);
            toClient.close();
            // 错误处理
        } catch (IOException e) {
            // 得到向客户端输出文本的对象
            PrintWriter toClientpw;
            try {
                toClientpw = response.getWriter();
                response.setContentType("text/html;charset=utf-8");
                toClientpw.write("无法打开图片!");
                toClientpw.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        } finally {
            if (toClient != null) {
                try {
                    toClient.close();
                } catch (IOException e) {
                    // e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 上传文件
     */
    public void uploadFile() {
        
        System.out.println(uploadContentType);
        
        String para = request.getParameter("para1");
        
        System.out.println(para);
        // 获取文件类型
        String type = uploadFileName.substring(uploadFileName.lastIndexOf("."),
                uploadFileName.length());// 得到文件的类型
        // 生成文件名
        String saveFileName = "fx_" + System.currentTimeMillis() + type; // 输出文件名称
        uploadFile(uploadFileName, saveFileName, upload,BASEPATH);
    }
    
    public static boolean uploadFile(String name, String saveFileName,
            File file, String uploadpath) {
        boolean b = false;
        try {
            // 上传文件
            File uploadfilepath = new File(uploadpath);
            if(!uploadfilepath.exists()){
                uploadfilepath.mkdirs();
            }
            InputStream in = new FileInputStream(file);
            File uploadFile = new File(uploadpath, saveFileName);
            OutputStream out = new FileOutputStream(uploadFile);
            byte[] buffer = new byte[1024 * 1024 * 10];// 设置文件上传最大值10M
            int length;
            while ((length = in.read(buffer)) > 0) {
                out.write(buffer, 0, length);
            }
            in.close();
            out.close();
            b = true;
        } catch (Exception e) {
            e.printStackTrace();
            b = false;
        }
        return b;
    }
    public static boolean deleteFile(String filePath) {
        boolean b = false;
        try {
            File file = new File(filePath);
            file.delete();
            b = true;
        } catch (Exception e) {
            e.printStackTrace();
            b = false;
        }
        return b;
    }
    
    public static void isExists(String path){
        File file = new File(path);  
        //判断文件夹是否存在,如果不存在则创建文件夹  
        if(!file.exists()){
            file.mkdir();
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++实现HTTP上传 的相关文章

随机推荐

  • Anaconda中如何查看已经安装的包

    1 前言 感谢网友 流风 xff0c 飘然的风 提供的帮助 原文链接如下 xff1a https www cnblogs com zdz8207 p ai Anaconda html 2 问题描述 今天学习计算机视觉的时候 xff0c 遇到
  • STM32的HAL库开发系列 - 串口发送

    STM32的HAL库开发系列 串口发送 基本知识 USART xff1a 通用同步和异步收发器 UART xff1a 通用异步收发器 当进行异步通信时 这两者是没有区别的 区别在于USART比UART多了同步通信功能 单工 xff1a 数据
  • 完美解决调用“sudo rosdep init“命令时的报错

    在安装完毕Ubuntu系统后 xff0c 我们执行命令sudo rosdep init时往往会遇到如下报错 xff1a sudo rosdep init ERROR cannot download default sources list
  • Yolo算法详解

    Yolo原理 yolo v1 Yolo是一种目标检测算法 xff0c 目标检测的任务是从图片中找出物体并给出其类别和位置 xff0c 对于单张图片 xff0c 输出为图片中包含的N个物体的每个物体的中心位置 x y 宽 w 高 h 以及其类
  • 解决“fatal error: dynlink_nvcuvid.h: 没有那个文件或目录#include <dynlink_nvcuvid.h>“问题

    问题描述 系统 Ubuntu18 04 安装OpenCV 3 4 0 报错 In file included from home zpj CLionProjects linuxidcbuild modules cudacodec openc
  • winform实现控件透明(实现真透明)

    使用BackColor 61 Color Translate这种方法只能实现和背景色一样但是不是真的透明 xff0c 控件后面的控件还是看不到 1 首先写一个基类 using System using System Collections
  • Python模拟SSH登录字符图形菜单

    本文说明如何使用Python模拟SSH登录字符图形菜单 xff08 不知道这种菜单叫啥名字 xff0c 姑且这么叫 xff09 xff0c 并选择相应的菜单项进行操作 以下图为例 xff0c 在SSH成功登录后 xff0c 选择第7行的改密
  • 安全产品,如何从idea到可落地实现

    安全产品 xff0c 如何从idea到可落地实现 前言Step1 xff1a 用一句话描述产品要解决的问题 xff08 What xff09 Step2 xff1a 给出用户故事 xff08 Why xff09 Step3 xff1a 分析
  • LDAP认证

    注 xff1a 本文由网络公开资料整理而来 xff0c 如有错误 xff0c 欢迎指正 LDAP xff08 Lightweight Directory Access Protocol xff09 是目录服务 xff08 DAP xff09
  • 计算机博弈大赛参赛程序算法总结

    背景 前两年的全国计算机博弈大赛的爱恩斯坦棋棋种赛我都有参加 14年采用的是极大极小算法 xff0c 那个时候还不太懂搜索算法的优化 xff0c 所以算法就是最原始的极大极小搜索 xff0c 没有做任何剪枝 15年我在上一年的算法基础上加入
  • 常见硬件通信协议总结

    xff08 正好手上的nodemcu支持UART SPI I2C协议 xff0c 所以这篇文章干脆就用nodemcu来分析协议了 xff09 UART 用逻辑分析仪捕捉nodemcu init lua给上位机发送 A xff1a span
  • 我们都被监控了?揭秘全球电信网络7号信令(SS7)漏洞

    From xff1a https www ithome com html it 278270 htm 最近 xff0c 一篇报道 黑客可以通过电话号码监控你的一举一动 xff0c 里面描述因为全球电信网络7号信令 xff08 SS7 xff
  • 使用route add添加路由,使两个网卡同时访问内外网

    route add命令格式 xff1a route f p Command Destination mask Netmask Gateway metric Metric if Interface 通过配置电脑的静态路由来实现同时访问内外网的
  • 手机自动访问generate_204

    近来写WiFi钓鱼demo xff0c 需要让手机连接 WiFi 后自动跳转到指定网页 xff0c 于是对手机进行dns拦截 在对手机的流量分析中发现一件很神奇的事 xff0c 手机接入WiFi后会自动访问 generate 204 以下是
  • MT7621方案 LED 灯控制 (基于OpenWrt平台)

    注 xff1a 出处不明 xff0c 最开始是在这里看到的 xff0c 图竟然没有 没有 相关资料也几乎木有 datasheet里也没有寄存器配置说明 MT7621还真是坑爹啊 xff01 目前市面上大部分路由器方案是基于MT7620的 x
  • ROS分布式通信,Jetson Nano 与PC机通信

    Jetson Nano 与PC机通信 1 环境2 SSH安装3 修改hosts文件4 修改环境变量文件 xff5e bashrc5 测试 1 环境 PC笔记本 xff1a Ubuntu 18 04 5 LTS Jetson Nano Ubu
  • .Net6.0系列-6 .Net 6LinQ(二)常用扩展方法

    一 本节学习LinQ的扩展方法 LinQ的where返回的IEnumerable 所有的括号中都可以写lamada表达式 list 数组等都可以用LinQ 以下这些方法都是可以和Where一起使用的 Count 返回的是满足条件的个数 An
  • postman简单上手教程

    1 xff1a postman浏览器已经停止更新了 xff0c 所以下面介绍的是app版本 2 xff1a 打开postman xff0c 创建自己的测试目录 xff0c 点加号创建 xff0c 这里我创建了test project 3 x
  • 实战microPython(06)-OLED屏的使用(2)

    实战microPython 06 OLED屏的使用 2 David Zou 2018 11 27 大家好 xff0c 上次介绍了OLED显示屏的相关知识 xff0c 今天 xff0c 我们进入实战 xff0c 学习如何使用OLED显示屏 如
  • C++实现HTTP上传

    插件中需要一个上传文件的功能 xff0c 我跟老大说 xff0c 我想FTP上传 xff0c 老大一瞪眼 xff0c 那还得再布个FTP服务器 xff0c 直接用HTTP上传多简单 那么C 43 43 如何将文件上传HTTP服务器上呢 xf