c ++ - Hvordan genbruges vektor med indstillede elementer?

Indlæg af Hanne Mølgaard Plasc

Problem



Så jeg streamer mit Rasperry Pi kamera til min computer ved hjælp af mit program, men. Vektoren nedenfor viser mig problemer.Det giver mig std::bad\_alloc efter ca. 30 sekunders streaming. Er der nogen måde at genbruge denne vektor over og igen i en loop (fx resize, clear)?
Her er den forenklede kode:


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
}

Bedste reference


TCP er en streamingprotokol. Det har intet begreb om meddelelser. At skrive 10.000 byte i den ene ende af forbindelsen betyder ikke, at alle 10.000 bytes vil komme til modtageren og være tilgængelige alle på én gang.


Som følge heraf arbejder recv med hvad der er. Den returnerer, hvad der er ledigt, og hvis der ikke er noget tilgængeligt recv, venter, indtil data bliver tilgængelige. Dette betyder, at hvis du beder om 10.000 bytes, kan du komme overalt mellem 1 byte og 10.000 byte helt på netværksstablerne, det maksimale antal data, der kan gå i en IP-pakke og for mange andre variabler, der skal listes.





recv(Connection, received\_message, sizeof(received\_message), NULL);


kan returnere, før den modtager alle received\_message. fileSize vil beregnes ud fra dårlig indgang, sandsynligvis en streng, der ikke afsluttes og løber fra slutningen af ​​bufferen, der udløser udefineret opførsel, og affaldet giver bort affald.


Denne forkerte fileSize bruges til at dimensionere en vector, som nu næsten helt sikkert vil være den forkerte størrelse. Hvis det er for lille,


recv(Connection, &fileData[0], CHUNK\_SIZE, 0);


kan løbe i slutningen af ​​vector for mere udefineret adfærd. Hvis det er for stort, kan systemet muligvis ikke allokere lagring til vector, fordi der ikke er tilstrækkelig sammenhængende lagerplads til rådighed. Dette ser ud til at være, hvad der er sket med OP.


Løsning: Løft alle opkald til recv, indtil den ønskede mængde data er ankommet, inden du fortsætter. Skriv i en alternativ sti for at håndtere lukkede eller fejlede forbindelser. Alle opkald skal læse den korrekte mængde data eller


recv(Connection, &fileData[0], CHUNK\_SIZE, 0);


kunne afslutte tidligt at forlade det næste


recv(Connection, received\_message, sizeof(received\_message), NULL);


at læse en del af billedet som received\_message, hvilket resulterer i en fileSize hver bit så sindssyg, som om received\_message ikke var helt fyldt.


Overvej også at indstille en timeout på recv, så du har mulighed for at læse et udgangs flag, hvis du ønsker at afslutte programmet. Ellers kan det evigt blokere for data, der aldrig kommer.

Andre referencer 1


Du kan nemt genbruge din std::vector som denne:


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
}


Et par noter:



  • Håndter begivenheden, at den første recv ikke modtager sizeof(received\_message) bytes (i øjeblikket beskyttet af assert)

  • Du skal definere maxFileSize

  • Medtag overskrifterne <cassert>, <exception> og <string>

  • Kompilér ved hjælp af -std=c++11