[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
Extended_mix
Jel make clean mora obrisati i txt datoteke koje stvorili izvođenjem programa?