2

几天来我一直在尝试将整个PNG读入一个字符串,所以我可以通过winsock2将它上传到服务器,它似乎在几个字符或某种换行符后停止读取文件,是否有任何特殊原因以及解决它的方法。

我已经尝试了很多解决方案,现在这开始让我发疯了。我正在使用的当前代码如下

std::ifstream in ("some.png", ios::in|ios::binary|ios::ate );
std::string contents;
if (in)
{           
    in.seekg(0, in.end);
    contents.resize(in.tellg());
    in.seekg(0, in.beg);
    in.read(&contents[0], contents.size());
    in.close();
    length = contents.size();        
}

我不知道问题可能是什么,因为我对 c++ 比较陌生,所以我已经在谷歌上拖了几天,但没有任何可行的解决方案。

请帮忙

UPDATE 代码发布到服务器

    WSADATA wsa;

        if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    return;


    SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

            if (fd < 0)     
                throw;

            SOCKADDR_IN service;

    service.sin_family    = AF_INET;
    service.sin_port      = htons(80);
    LPHOSTENT host        = gethostbyname("127.0.0.1");

            if (!host)          
                throw;

            service.sin_addr = *((LPIN_ADDR)*host->h_addr_list);

            if (connect(fd, (SOCKADDR *)&service, sizeof(service)) < 0)     
                throw;

    int length ;

    std::ifstream in (CCFileUtils::fullPathFromRelativePath("back.png"), ios::in|ios::binary|ios::ate );
    std::string contents;

            if (in){

            in.seekg(0, in.end);
        contents.resize(in.tellg());
        in.seekg(0, in.beg);
        in.read(&contents[0], contents.size());
        in.close();
        length = contents.size();
    }else

        std::string str =
        "POST /index.php HTTP/1.1\r\n"
        "Host: metapps.co.uk\r\n"
        "Accept: */*\r\n";

        char buffer1 [50];  
        str.append(  "Content-Length: 121\r\n" );
        str.append(  "\r\n" );

        str.append(  "Content-Disposition: form-data; name=\"tmp\";filename=\"photo.png\"\r\n" );
        str.append(  "Content-Type: image/dds\r\n" );
        sprintf (buffer1, "Content-Length: %d\r\n", length);
        str.append( buffer1 );
        str.append( contents    );
        str.append(  "\r\n\x01A\r\n" );

        // send str ...
        send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
        char ret[1024];

        recv(fd,ret,strlen(ret),0);

        closesocket(fd);
        WSACleanup();
}

更新 2

它与 Null 终止符字符串和 append 方法有关

如果我做

str.append( "he\0llo"   );

服务器只会显示“他”

如果我做

str.append( "hello" );

我打个招呼,希望这些信息能带来解决方案

4

4 回答 4

3
    send(fd, str.c_str() , strlen( str.c_str() ) +1 , 0);
        char ret[1024];

strlen( str.c_str() ) +1会告诉你输出中第一个 0 字节的位置,而不是字符串的长度。字符串的长度最好通过str.size()来选择。


此外,正如WhosCraig 提到的,您正在调用strlen(ret)whereret未初始化。相反,使用

  std::array<char, 1024> ret;
  recv(fd,ret,ret.size(),0);

或者可能更动态的东西。

于 2013-08-23T22:11:18.303 回答
1

一种方式[1]

std::ifstream in("some.png", ios::binary);
std::vector<unsigned char> contents(std::istreambuf_iterator<char>(in), {});

其他

std::ostringstream oss;
oss << in.rdbuf();
std::string contents = iss.str();

正如其他人所指出的,通常没有必要一次将全部内容保存在内存中。它会导致可伸缩性问题。尽可能避免它。


[1]如果您的编译器受到标准挑战,请将其分解:

std::istreambuf_iterator<char> f(in), l;
std::vector<unsigned char> contents(f, l);
于 2013-08-23T22:33:16.137 回答
0

&contents[0]用于获取字符串使用的内部缓冲区的地址。据我所知,在调用 .c_str() 之前,这个缓冲区不能保证是连续的,甚至不能保证大小正确,所以你不能传递地址。

用于std::vector<char>原始std::array<char, n>二进制数据。它们总是保证有顺序缓冲区。

哦,顺便说一下,没有必要将整个文件读入一个大缓冲区。只需分段读取和写入。

于 2013-08-23T22:32:09.843 回答
0

我解决了!

我发送的标头 Content-length 的固定长度为 121

       str.append(  "Content-Length: 121\r\n" );

所以服务器因此将消息体截断到这个长度,我不知道服务器如此重视这个值,如果它太大也会抛出 500 错误。

为消息正文发送正确的长度可以修复它。

我还将标题与消息正文分开并使用了

std::vector<char> 

按照@youdontneedtothankme 存储消息正文

感谢所有回复和评论,帮助我在经历了漫长的一周的挫折后找到了问题的根源,我的生活现在可以继续了,哈哈:)

堆栈溢出 FTW!

于 2013-08-24T12:50:43.137 回答