Kevin Duarte
Kevin Duarte

Reputation: 438

How to re-use vector with set elements?

So I'm streaming my Rasperry Pi camera to my computer using my program but. The vector listed below is giving me problems. It gives me std::bad_alloc after about 30 seconds of streaming. Is there any way to reuse this vector over and over again in a loop (e.g resize, clear)? Here is the simplified code:

while(isRunning)
{
    recv(Connection, received_message, sizeof(received_message), NULL); //receiving the size of image in bytes
    fileSize = atoi(received_message);

    std::vector<char> fileData(fileSize); //<- this vector is giving me problems

    recv(Connection, &fileData[0], CHUNK_SIZE, 0); //Receiving the image

    //The code loops over and over again
}

Upvotes: 2

Views: 145

Answers (2)

user4581301
user4581301

Reputation: 33952

TCP is a streaming protocol. It has no concept of messages. Writing 10,000 bytes in at one end of the connection does not mean all 10,000 bytes will arrive at the receiver and be available all at once.

As a result, recv works with what is has. It returns whatever is currently available, and if nothing is available recv waits until data becomes available. This means if you ask for 10,000 bytes you may get anywhere between 1 byte and 10,000 bytes entirely at the whim of the network stack, the maximum amount of data that can go in one IP packet, and too many other variables to list.

So

recv(Connection, received_message, sizeof(received_message), NULL);

may return before it receives all of received_message. fileSize will computed from bad input, most likely a string that isn't null terminated and runs off the end of the buffer triggering undefined behaviour, and garbage in gives garbage out.

This incorrect fileSize is then used to size a vector which will now almost certainly be the wrong size. If it is too small,

recv(Connection, &fileData[0], CHUNK_SIZE, 0);

may run off the end of the vectorfor more undefined behaviour. If it is too large, the system may not be able to allocate storage for the vector because there isn't enough contiguous storage available. This appears to be what has happened to OP.

Solution: Loop all calls to recv until the required amount of data has arrived before proceeding. Write in an alternate path to handle closed or failed connections. All calls must read the correct amount of data or

recv(Connection, &fileData[0], CHUNK_SIZE, 0);

could exit early leaving the next

recv(Connection, received_message, sizeof(received_message), NULL);

to read part of the image as received_message, resulting in a fileSize every bit as insane as if received_message was not completely filled.

Also Consider setting a timeout on recv so that you have a chance to read an exit flag should you wish to terminate the program. Otherwise it may block forever for data that will never arrive.

Upvotes: 2

Jonas
Jonas

Reputation: 7017

You can easily reuse your std::vector like this:

std::vector<char> fileData;

while(isRunning)
{
    ssize_t n = recv(Connection, received_message, sizeof(received_message), 0); //receiving the size of image in bytes
    if (n < 0)
        throw std::runtime_error(std::string("Connection error (getting fileSize)") + strerror(errno));
    assert(n == sizeof(received_message));

    fileSize = atoi(received_message);

    if (fileSize > maxFileSize or fileSize == 0)
        throw std::runtime_error("Invalid fileSize " + std::to_string(fileSize));

    fileData.resize(fileSize);

    size_t received = 0;
    while (received < fileSize)
    {
        ssize_t n = recv(Connection, fileData.data() + received, fileSize - received, 0); //Receiving the image
        if (n < 0)
            throw std::runtime_error(std::string("Connection error (getting image)") + strerror(errno));
        received += n;
    }
    //The code loops over and over again
}

A few notes:

  • Handle the event that the first recv does not receive sizeof(received_message) bytes (currently protected by the assert)
  • You should define maxFileSize
  • Include the <cassert>, <exception> and <string> headers
  • Compile using -std=c++11

Upvotes: 0

Related Questions