Ovu stranicu je najbolje pregledavati u modernom internet pregledniku s omogućenim JavaScriptom.

[MREPRO] 3. domaća zadaća - 2020/2021

ruza0001

Kako poslati sadrzaj datoteke? Tocnije kako ga dohvatiti iz datoteke, spremiti u varijablu (?) i onda poslati… C previse komplicira ovu zadacu…


Bisenberg

rozy Imas funkciju fgets koja uzima liniju po liniju datoteke, uguglaj kako se koristi, samo stavis while (fgets(….) ) send().
To je za tekstualne datoteke, nisam siguran ako su u binarnom zapisu ima li razlika, vjerojatno ima


__builtin_popcount

rozy
Ja napravim buffer od 1 KiB, pa koristim read da učitam iz datoteke koju sam prethodno otvorio s open. read mi vrati broj stvarno pročitanih okteta, pa toliko onda pošaljem sa send. Ta brojka je bitna jer veličina datoteke možda nije višekratnik 1 KiB, pa ne smijem svaki put na klijent slijepo slati cijeli buffer. Taj postupak s čitanjem i slanjem ponavljam dokle god mi read ne vrati da je pročitano 0, što znači da sam na kraju datoteke i da nema više bajtova.

Ja sam koristio Unix syscallove open i read, ali postoje i funkcije C standard libraryja fopen i fread. Kako u ostatku ovog programa puno koristim syscallove, odlučio sam ih i koristiti za čitanje datoteka radi ujednačenosti, te mi je izgledalo kao da je lakše handleati errore u syscallovima. Negativna povratna vrijednost je uvijek greška za read, dok fread vraća 0 i kad dođe do kraja datoteke, i ako se dogodi greška, pa s feof/ferror provjeravati koje od tog dvoje se dogodilo. Standardne funkcije bih svakako koristio kad bih pisao neki prenosivi program koji mora raditi i na Windowsima, ali se ovdje jako oslanjamo na Unix syscallove pa nema nikakve potrebe za prenosivosti.


ruza0001

std::popcount a u kojem obliku prenosis ovaj zahtjev sto su prva 4 bajta offset, a nakon toga ime datoteke. Jel to obicni string pa onda iz njega iscitat prvo offset pa dalje filename ili? Totalno sam bez ideje


mstaver

Pazite da vam tcpserver radi za zahtjeve poslane u više TCP segmenata:
npr. offset(2 bajta) + offset(2 bajta) + prvi dio filename + ostatak filename (ovo Miljenko provjerava)

Ovo možete napraviti tako da offset citate sa readn (pogledajte primjer readn u skripti), a filename treba citati sa socketa dok god ne naiđete na delimiter \0. Ovo možete napraviti tako da čitate byte po byte i svaki byte provjeravate ako je on delimiter (nije baš efikasno jer stalno radite sys pozive) ili da pročitate sve sa socketa u neki buffer pa ručno tražite delimiter u tom bufferu i ak ga nema spremite buffer i čitate opet.


__builtin_popcount

rozy
Offset napravim tako da sam napisao funkciju koja čita točno neki broj bajtova. Sam sam ju pisao jer u tom trenutku nisam bio svjestan da u knjizi postoji implementacija toga na stranici 40 (readn). Implementacija iz knjige:

ssize_t
readn(int fd, void* vptr, size_t n){
    size_t nleft;
    ssize_t nread;
    char   *ptr;

    ptr = vptr;
    nleft = n;

    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) < 0) {
            if(errno == EINTR)
                nread = 0; /* and call read() again */
            else
                return (-1);
        } else if (nread == 0) {
            break;         /* EOF */
        }
        nleft -= nread;
        ptr += nread;
    }
    return (n - nleft);    /* return >= 0 */
}

Za filename sam napisao drugu funkciju koja čita bajt po bajt dok ne naiđe na '\0'. Ona je donekle slična ovoj readn, samo što uvijek čita 1 bajt i pointer uvećava za 1 dokle god ne naiđe na '\0'.

Kako bih izbjegao mogućnost buffer overflowa, funkcija prima i maksimalnu duljinu filenamea i prestaje ako pročita toliko bajtova, a ne naiđe na '\0'.


ruza0001

kako sloziti ovaj zahtjev od klijenta koji je offset + filename? Ja pokusavam offset ko int imat, i onda ga samo pretvorit u string i na to dodat filename, ali cini mi se da je to krivi nacin, pa ako netko ima ideju neku..


BigZ1

rozy jednostavnije rjesenje se zove struktura. (nju mozes poslat) (imao isti problem)


Mariox

rozy bez pretvaranja u string radi, isprobao sam. Int u linuxu je 4 byte-a:
klijent (pošiljatelj)

    int offset = htonl(777);
    writen(sockfd, &offset, 4);

server (primatelj)

    int offset;
    readn(newfd, &offset, 4);

    offset = ntohl(offset);
    
    debug_printf("offset je %d\n", offset); // ispise 777

nakon toga sam mislio slati filename.
Primatelj filename-a (server) ce citat byte po byte dok nedođe do \0 kao sto je popcount opisao


Mariox

Mariox
EDIT: evo na isti nacin odmah iza toga jos jedan writen i readn da se posalje filename, samo bez pretvaranja byte ordera. Za sada sam napravio da se uvijek salje svih n=FILENAME_MAX bytova. Kasnije cu optimizirati da se salje samo koliko je filename string zapravo dugacak, no onda ima vise posla za primatelja


puufi

Ako predamo prazan zadatak3 ili barem c fileove koji ne rade jel se to racuna kao predana zadaca?


ruza0001

puufi pa vjerovatno da, samo 0 bodova i tjt… napisi im neki zanimljivi print kad runnaju i tjt 😆


ruza0001

jel imao netko problem da mu fwrite, kad appenda na file dodaje u novi red uvijek


Mariox

rozy evo ja sam sada dosao do istog problema, ali ja koristim pwrite(). Zadnji line u svakom text file-u mora imati new line na kraju (koji se automatski dodaje kada save-as file u geany-u npr). Zbog toga append uvijek ide u novi red.


Mariox

kako da pretvorim service name u string ili integer?


ruza0001

Mariox ja ga spremam ko string uvijek, i onda ce getaddrinfo() vidjet jel valjan ili nije, to mi je asistent na odgovaranju labosa predlozio bio, jer sam ja koristio samo integer bio..


Mariox

Mariox evo uspio sam rijesiti pomocu pwrite(). Nisam otvorio u append modu nego u write modu, a write mod ne obrise sadrzaj datoteke. Samo sam onda pomocu pwrite() pisao na dobru poziciju


Extended_mix

Jel make clean mora obrisati i txt datoteke koje stvorili izvođenjem programa?