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?
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.
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".
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.
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.
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.
Tosiaan. Ihmettelin tuota viritelmaa hetken, ja unohdin sen saman tien. Lienee parempi pysya erossa koodista kunnes nuhakuume helpottaa.
Aihe on jo aika vanha, joten et voi enää vastata siihen.