使用C / C ++中的winsocks发送原始请求(http post文件数据)

时间:2013-07-08 10:08:20

标签: c++ file-upload winsock2

我正在开发一个小项目,该项目将使用c ++应用程序发送文件(图像),并通过 http (无ftp)在Web服务器上接收。

我使用 winsocks 发送查询,但我的问题是:

    std::string query=
    "POST /test/upload.php HTTP/1.1\r\n"
    "Host: site.net\r\n"
    "User-Agent: User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36\r\n"
    "Connection: Keep-alive\r\n\r\n"
    "Content-Length: "+FileSize+"\r\n"
    "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"

    "------WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"
        "Content-Disposition: form-data; name=\"tmp\"; filename=\"photo.jpg\"\r\n"
        "Content-Type: image/jpeg\r\n\r\n"
        +StrData+
    "------WebKitFormBoundarym9PgiUg6fjxm2Hpr--\r\n";

我需要把我文件的HEX放在这里 - > StrData ,但我不知道该怎么做?...

1 个答案:

答案 0 :(得分:2)

不,您不需要以HEX格式发送文件数据。您需要按原样发送文件的原始原始二进制数据。假设文件的大小很小,您可以将其填入std::string原样。

顺便说一句,您的请求格式不正确 - \r\n标题上的Connection太多了。额外的\r\n取代了最后一个标头。并且不要将Content-Length标头与multipart内容类型一起使用,因为它们是自我终止的 - 特别是因为您无论如何都指定了错误的值。如果要指定Content-Length,则必须先计算完整MIME数据的长度,然后再创建继续使用的标头。

请改为尝试:

std::ifstream File("filename", std::ios::in | std::ios::binary | std:::ios::ate);
if (file)
{
    std::ifstream::pos_type FileSize = File.tellp();
    File.seekg(0);

    std::string StrData;
    if (FileSize > 0)
    {
        StrData.resize(FileSize);
        File.read(&StrData[0], FileSize);
    }

    File.close();

    std::string query =
        "POST /test/upload.php HTTP/1.1\r\n"
        "Host: site.net\r\n"
        "User-Agent: User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36\r\n"
        "Connection: Keep-alive\r\n"
        "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"
        "\r\n"
        "------WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"
        "Content-Disposition: form-data; name=\"tmp\"; filename=\"photo.jpg\"\r\n"
        "Content-Type: image/jpeg\r\n"
        "\r\n"
        +StrData+
        "\r\n"
        "------WebKitFormBoundarym9PgiUg6fjxm2Hpr--\r\n";

    // send query ...
}

话虽如此,最好不要尝试将整个HTTP请求填充到单个std::string中。首先发送初始请求标头,然后发送原始文件数据,然后最后发送终止边界。例如:

std::fstream File("filename", std::ios::in | std::ios::binary);
if (file)
{
    char chunk[1024];
    std::streamsize chunksize;

    std::string str =
        "POST /test/upload.php HTTP/1.1\r\n"
        "Host: site.net\r\n"
        "User-Agent: User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36\r\n"
        "Connection: Keep-alive\r\n"
        "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"
        "\r\n"
        "------WebKitFormBoundarym9PgiUg6fjxm2Hpr\r\n"
        "Content-Disposition: form-data; name=\"tmp\"; filename=\"photo.jpg\"\r\n"
        "Content-Type: image/jpeg\r\n"
        "\r\n";

    // send str ...

    do
    {
        chunksize = File.readsome(chunk, sizeof(chunk));
        if (chunksize < 1)
            break;

        // send chunk up to chunksize bytes ...
    }
    while (true);

    File.close();

    str =
        "\r\n"
        "------WebKitFormBoundarym9PgiUg6fjxm2Hpr--\r\n";

    // send str ...