Domanda

For days I have been trying to read an entire PNG into a string, so I can upload it to a server via winsock2, it appears to stop reading the file after a few characters or a some sort of line break, is there any particular reason and a way of solving it.

I have tried many many solutions and this is now starting to drive me insane. The current code I am using is as follows

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();        
}

I have no idea what the problem could be, as I am relatively new to c++, I have trolled through google for days with no working solution.

Please help

UPDATE code posting to the server

    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();
}

Update 2

Its something to do with the Null terminator string and the append method

If I do

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

The server will only show "he"

If I do

str.append( "hello" );

I get hello, hopefully this info, can lead to a solution

È stato utile?

Soluzione 4

I solved it!

The header Content-length I was sending were a fixed length of 121

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

So the server was therefore truncating the message body to this length, I had no idea the server took this value so seriously, if it were too big it would also throw a 500 error.

Sending the correct length for the message body fixed it.

I also separated the headers from the message body and used a

std::vector<char> 

to store the message body as per @youdontneedtothankme

Thanks for all replies and comments, helped me get to the bottom of the issue after one long week of frustration, my life can now move on lol :)

Stackoverflow FTW!

Altri suggerimenti

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

strlen( str.c_str() ) +1 will tell you the position of the first 0 byte in the output, and is NOT the length of the string. The length of the string is best optained via str.size() instead.


Also, as WhosCraig mentioned, you're calling strlen(ret) where ret is uninitialized. Instead, use

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

or potentially something more dynamic.

One way[1]:

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

Another

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

As others have noted, it's usually not necessary to have the full contents in memory at a single time, though. It leads to problems with scalability. Avoid it if at all possible.


[1] If your compiler is standards challenged, break it up:

std::istreambuf_iterator<char> f(in), l;
std::vector<unsigned char> contents(f, l);

You are using &contents[0] to get the address of the internal buffer used by the string. As far as I know, this buffer is not guaranteed to be sequentiental, or even have the right size before you call .c_str(), so you just can't pass the address around.

Use std::vector<char> or std::array<char, n> for raw binary data. They are allways guaranteed to have sequential buffers.

Oh, and by the way, there is no need to read the whole file into one big buffer. Just read and write it piecewise.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top