2013-07-08 31 views
2

我正在开发一个小型项目,该项目将使用C++应用程序发送一个文件(图像),并通过网页服务器接收它http(no ftp )。用C/C++中的winsocks发送原始请求(http post文件数据)

我用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是,但我不知道该怎么办那??

回答

2

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

顺便说一下,您的请求格式错误 - 您在Connection标头上有太多\r\n。额外的\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 ... 
+0

我认为你的权利这个版本更好,我会尝试,但我可以发几次这样的查询? – user2417534

+0

是的。与UDP不同,TCP是一个字节流。您不必在单个send()调用中发送所有内容。你可以使用多个send()调用。 –