Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: SDL_Net ja kuvan lähettäminen verkon yli

Burton [03.09.2011 18:50:03]

#

Tervehdys.

Minulla on pienoinen ongelma. Olen kehitellyt mielenkiinnosta ohjelmaa, joka lähettää kuvan verkon yli koneelta koneelle. Apunani C ja SDL_Net. Käytän client -> server -mallia, jossa client ottaa yhteyden aina päällä olevaan serveriin ja alkaa lähettää dataa. Kuva ei kuitenkaan tallennu vastaanottavalle koneelle oikein. Tiedostokoko on aivan sama kuin lähettäjäkoneessa, mutta Windowsin kuvankatseluohjelma sanoo, että kuvadata on korruptoitunut.

Liitän tähän pari näytettä koodistani.

// kuvan lukeminen muistiin, client-puoli
long lSize;
char *buffer;
size_t result;

FILE *T = fopen("image.png", "rb");

fseek(T, 0, SEEK_END);
lSize = ftell(T);
rewind(T);

buffer = (char*)malloc(sizeof(char)*lSize);
result = fread(buffer, 1, lSize, T);

fclose(T);
// kuvan lähettäminen serverille
// seuraava koodi tapahtuu kuvan koon lähettämisen jälkeen. Client ilmoittaa serverille, kuinka paljon muistia on varattava

K = lSize / 512; // lähetettävät paketit ovat 512 tavun kokoisia
for (i = 1; i <= K; i++) {
    // K * 512 tavua lähtee matkaan tässä silmukassa
    SDLNet_TCP_Send(sd, (void *)buffer, 512);

    // en ymmärrä tarkalleen ylläolevan funktion toimintaa
    // mutta oletan, että se lähettää 512 ensimmäistä alkiota matkaan
    // allaoleva silmukka pakkaa alkioita nolla-alkiota kohti jokaisen
    // lähetyksen jälkeen
    for (l = 512; l < lSize; l++)
        buffer[l - 512] = buffer[l];
}
// lähetetään loput tavut
SDLNet_TCP_Send(sd, (void *)buffer, (int)(lSize - K * 512));

Serverin puolella data vastaanotetaan 512 tavun kokoisina paketteina SDLNet_TCP_Recv-funktiolla. En tiedä aivan tarkalleen, miten suuri viive pakettien vastaanottamisessa on. Pitäisikö tähän tehdä jonkinlainen tarkistus sen varalta, että paketit ovat varmasti saapuneet? Sillä client lähettää ne silmukassa aivan peräperään. Ehtiikö serveri vastaanottamaan ne kaikki järkevästi? No mutta, palataan koodiin.

Kun palikat on vastaanotettu ja ne on koottu buffer_copy-taulukkoon, jonka alkioiden määrä on ensimmäisenä vastaanotettu lSize, kuvadata kirjoitetaan tiedostoon näin:

T = fopen("image_copy.png", "wb");
    fwrite(buffer_copy, 1, lSize, T);
fclose(T);

Tiedosto luodaan onnistuneesti, se on kooltaan lSize tavua, mutta kuvaa ei näy, eli jossain on tapahtunut virhe. Missä se mahtaa olla?

Deffi [03.09.2011 19:12:19]

#

Burton kirjoitti:

Pitäisikö tähän tehdä jonkinlainen tarkistus sen varalta, että paketit ovat varmasti saapuneet? Sillä client lähettää ne silmukassa aivan peräperään. Ehtiikö serveri vastaanottamaan ne kaikki järkevästi?

TCP huolehtii näistä puolestasi.

Burton kirjoitti:

Kun palikat on vastaanotettu ja ne on koottu buffer_copy-taulukkoon, jonka alkioiden määrä on ensimmäisenä vastaanotettu lSize, kuvadata kirjoitetaan tiedostoon näin:

T = fopen("image_copy.png", "wb");
    fwrite(buffer_copy, 1, lSize, T);
fclose(T);

Tiedosto luodaan onnistuneesti, se on kooltaan lSize tavua, mutta kuvaa ei näy, eli jossain on tapahtunut virhe. Missä se mahtaa olla?

Arvaan, että avaat tiedoston joka kerta uudelleen kun vastaanotat dataa. Käytät wb-moodia, jolloin jo olemassaoleva tiedosto ylikirjoitetaan. Siirrä serveripäässä fopen ja fclose vastaanottosilmukan ulkopuolelle.

edit. joo, K olikin yhden paketin koko ja lSize koko tiedoston.

Metabolix [03.09.2011 19:14:42]

#

Olisiko ihan mahdoton ajatus debugata koodia vielä esimerkiksi niin, että tulostaisit vaikka heksamuodossa taulukon alkua tuolla juuri ennen for-silmukkaa ja vastaavasti juuri ennen tallennusta? Luultavasti olet jossain kohti kirjoittanut lähetyksen ja vastaanoton epäyhteensopivasti – todennäköisimmin tiedoston koon lähetyksen kohdalla, jolloin esimerkiksi tiedosta "4 ABCD" ei päädykään kuvaksi "ABCD" vaan " ABC".

Burton [03.09.2011 19:24:22]

#

Deffi kirjoitti:

Arvaan, että avaat tiedoston joka kerta uudelleen kun vastaanotat dataa. Käytät wb-moodia, jolloin jo olemassaoleva tiedosto ylikirjoitetaan. Siirrä serveripäässä fopen ja fclose vastaanottosilmukan ulkopuolelle.

Tätä olisin voinut selventää.

Koodissa buffer_copy on lopullinen taulukkomuoto kuvalle. fwriteä käytetään vain ja ainoastaan ohjelman suorituksen lopussa. buffer-niminen taulukko vastaanottaa clientiltä dataa 512 tavun paketeissa ja ymppää ne sitten buffer_copyyn. Kaiken tämän suorituksen jälkeen data kirjoitetaan image_copy.png:hen.

Metabolix: Yritän debugata vähäsen ja palaan asiaan uudelleen.

jcd3nton [03.09.2011 20:49:14]

#

Burton kirjoitti:

buffer = (char*)malloc(sizeof(char)*lSize);

sizeof(char) on aina 1, ja C:ssa sijoittaessa void-pointteria ei tarvitse castia kirjoittaa. Voit siis sanoa yksinkertaisemmin

buffer = malloc(lSize);

Muista myos tarkistaa mallocin paluuarvo. Sama koskee freadia.

lainaus:

// lähetetään loput tavut
SDLNet_TCP_Send(sd, (void *)buffer, (int)(lSize - K * 512));

Buffer osoittaa edelleen puskurin alkuun.

Metabolix [03.09.2011 21:05:32]

#

jcd3nton kirjoitti:

Buffer osoittaa edelleen puskurin alkuun.

Entä sitten? Tuollahan on juuri sitä varten ihmeellinen purkkaviritelmä, jossa siirretään dataa puskurissa ympäriinsä.

Tietenkin tehokkaampaa olisi pitää data paikallaan ja muuttaa vain funktiolle annettavaa parametria: buffer + i * 512, kun i alkaa 0:sta.

jcd3nton [03.09.2011 21:14:29]

#

Tosiaan. Ihmettelin tuota viritelmaa hetken, ja unohdin sen saman tien. Lienee parempi pysya erossa koodista kunnes nuhakuume helpottaa.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta