Richard Stallman dnes v Liberci přednáší o svobodném softwaru a svobodě v digitální společnosti. Od 16:30 v aule budovy G na Technické univerzitě v Liberci. V anglickém jazyce s automaticky generovanými českými titulky. Vstup je zdarma i pro širokou veřejnost.
sudo-rs, tj. sudo a su přepsáné do programovacího jazyka Rust, nahradí v Ubuntu 25.10 klasické sudo. V plánu je také přechod od klasických coreutils k uutils coreutils napsaných v Rustu.
Fedora se stala oficiální distribucí WSL (Windows Subsystem for Linux).
Společnost IBM představila server IBM LinuxONE Emperor 5 poháněný procesorem IBM Telum II.
Byla vydána verze 4.0 multiplatformního integrovaného vývojového prostředí (IDE) pro rychlý vývoj aplikaci (RAD) ve Free Pascalu Lazarus (Wikipedie). Přehled novinek v poznámkách k vydání. Využíván je Free Pascal Compiler (FPC) 3.2.2.
Podpora Windows 10 končí 14. října 2025. Připravovaná kampaň Konec desítek (End of 10) může uživatelům pomoci s přechodem na Linux.
Již tuto středu proběhne 50. Virtuální Bastlírna, tedy dle římského číslování L. Bude L značit velikost, tedy více diskutujících než obvykle, či délku, neboť díky svátku lze diskutovat dlouho do noci? Bude i příští Virtuální Bastlírna virtuální nebo reálná? Nejen to se dozvíte, když dorazíte na diskuzní večer o elektronice, softwaru, ale technice obecně, který si můžete představit jako virtuální posezení u piva spojené s učenou
… více »Český statistický úřad rozšiřuje Statistický geoportál o Datový portál GIS s otevřenými geografickými daty. Ten umožňuje stahování datových sad podle potřeb uživatelů i jejich prohlížení v mapě a přináší nové možnosti v oblasti analýzy a využití statistických dat.
Kevin Lin zkouší využívat chytré brýle Mentra při hraní na piano. Vytváří aplikaci AugmentedChords, pomocí které si do brýlí posílá notový zápis (YouTube). Uvnitř brýlí běží AugmentOS (GitHub), tj. open source operační systém pro chytré brýle.
Řešení dotazu:
fread()
ti může přijít jen kousek – proto buffer a automat, který detekuje skutečný konec zprávy.
cesta/k/souboru'nulovy byte'soubortim, ze dvakrat po sobe zavolam na socket z klienta write() a az potom zavrit socket? Nejsem si jisty jak v takovem pripade pracuje accept(). Pokud by cekal na uzavreni klientskeho socketu tak by to snad slo ne? Nejak pseudo takto: Klient:
write(socket,"cesta") write(socket,soubor) close(socket)Tohle by mohlo fungovat pokud accept na strane serveru ceka. Ale nejsem si jisty timto chovanim.
cesta/k/souboru NULL délka soubor
tak můžete posílat i víc souborů v jednom spojení int sl_log(const char *caller, const char* message) { int fp; fp = open("/tmp/pb173_syslog", O_WRONLY); char *msg; if (fp == -1) { perror("Could not open the pipe\n"); exit(1); } asprintf(&msg, "%s^%s\n", caller, message); write(fp, msg, strlen(msg)); free(msg); close(fp); return 0; }Ktera pouziva strisku ^ jako oddelovac aznak pro konec radku jako indikator pro konec zpravy. Jak ale jeste jinak indikovat konec zpravy? V pripade, ze se do jedne message posle treba
radek1\nradek2\natd. Proste nejake jine oddeleni resp. ukonceni zpravy.
Ano, protokol urcite, ale muj dotaz smeroval spise k technickemu reseni: muzu napriklad na server poslat zpravu ve tvaru:Je jedno, aký oddeľovač bude použitý, alebo v akej štruktúre budú údaje, môže to byť XML, JSON, alebo kľudne dve bajtové postupnosti oddelené nulovým bajtom, ako je uvedené vyššie. Dôležité je, aby obe strany mali zhodné chápanie - t.j. PROTOKOL - toho, čo sa posiela. Protokol nie je nič viac, ako dohoda o formáte, štruktúre, či postupnosti krokov. No a ak máš pod kontrolou implementáciu na oboch stranách, môžeš si zvoliť vlastný protokol podľa ľubovôle (najmä, ak sa voláš Ľubo, že áno). Tak či tak, veci sú zvyčajne jednoduchšie, ak sa použije niečo, čomu rozumejú aj iné nástroje, ako tie Tvoje: riadky textu, CSV, alebo už vyššie zmienený JSON. Napoviem, že binárne údaje možno zakódovať napr. base64, aby sa dali bezpečne prenášať ako text. Nakoniec tak bude možné riešenie - alebo jeho časť - namiesto low-level kódovania v C poskladať v skriptovacom jazyku z existujúcimi nástrojmi. Ak však ide o akademickú úlohu a cieľom je naučiť sa práve to, ako to implementovať v C, predchádzajúci odstavec ignoruj, aspoň čo sa týka skriptovania a nástrojov; odporúčanie použiť podľa možnosti existujúci protokol či formát výmeny údajov stále platí.cesta/k/souboru'nulovy byte'soubor
accept()
je connect()
a opakem k write()
je read()
.
Volání accept()
pouze vyzvedává příchozí spojení, žádná data nečte. Tedy ze serverového filedescriptoru zavoláním accept()
oddělíš klientský, který už lze použít ke komunikaci. Všimni si, že ze serverového filedescriptoru nikdy nečteš.
Když vícekrát zavoláš write()
, data jsou uložena do bufferu a následně odesílána klientovi, který je získá pomocí read()
. Počet volání read()
neodpovídá počtu volání write()
.
Co se samotných dat týče, můžeš poslat naprosto cokoliv.
Pamatuj jen, že pokud se ti ztratí TCP spojení, nemáš nijak garantováno, která data klient přijal a která už se ztratila. Tedy úspěšný write()
znamená jen uložení dat do lokálního bufferu, nikoliv jejich doručení.
Jinak nepoužívej přímo read()
a write()
, jejich použití není zrovna triviální a má plno temných zákoutí. Raději nejprve zavolej na socket fdopen()
a pak použij fread()
, fwrite()
, fflush()
a fclose()
. Ušetříš si starosti a podivné chyby.
strcat(buf,fbuffer);Zprava je ve tvaru:
flag:je_adresar:delka_nazvu_domovskeho_adresare:delka_cesty:cesta/k/souboru:soubor
void send_msg(char *message, char *path) { int len; char buf[1024]; FILE *file; char *fbuffer; unsigned long fileLen; strcpy(buf, message); file = fopen(path, "rb"); if (!file) { fprintf(stderr, "Unable to open file %s", message); return; } fseek(file, 0, SEEK_END); fileLen=ftell(file); fseek(file, 0, SEEK_SET); fbuffer=(char *)malloc(fileLen+1); if (!fbuffer) { fprintf(stderr, "Memory error!"); fclose(file); return; } fread(fbuffer, fileLen, 1, file); fclose(file); strcat(buf,fbuffer); len = strlen(buf); buf[len++] = '\n'; buf[len] = '\0'; send(sockfd, buf, strlen(buf), 0); free(fbuffer); free(message); message = NULL; }Server zpravu prijime a cely buffer posle na zpracovani do fce, handle_msg, kde se vse rozparsuje (ty printf tam mam zatim jen pro debugovaci ucely). Spadne mi to na:
File Cannot be opened file on serverPritom promenna home (cesta do adresare serveru, kam se prijaty soubor ulozi) se vypise spravne.
void handle_msg(char *buf) { char *p_str; char file[1024]; char home[1024]; char path[1024]; int j; int flag; int hm_len; int par_len; int is_dir; strcpy(home, buf); j = 0; p_str = strtok(home, ":"); while (p_str != NULL) { if (j == 0) flag = atoi(p_str); else if (j == 1) is_dir = atoi(p_str); else if (j == 2) hm_len = atoi(p_str); else if (j == 3) par_len = atoi(p_str); else if (j == 4) strcpy(path, p_str); else strcpy(file, p_str); p_str = strtok(NULL, ":"); j++; } printf("flag: %d\n", flag); printf("isdir: %d\n", is_dir); printf("hmlen: %d\n", hm_len); printf("parlen: %d\n", par_len); printf("path: %s\n", path); memset(home, '\0', sizeof (home)); strcpy(home,mydir); // mydir je nazev korenoveho adresare serveru strcat(home, path + hm_len); //k mydir se prida prislusna cesta - adresarova struktura musi byt stejna u serveru i klienta printf("home: %s\n", home); //vytiskne se korektne if ((flag == IN_CREATE)) { if(is_dir) mkpath(home, S_IRWXU | S_IRWXG | S_IRWXO); else { FILE *fr = fopen(home, "wb"); if(fr == NULL) printf("File Cannot be opened file on server.\n"); //fr je z nejakeho duvodu NULL fwrite (file , sizeof(char), sizeof(file), fr); fclose(fr); } } } void *thread_reader(void **_client) { client_t *client = *_client; char *buf = NULL; int len = 0; int i; char *rest; while (1) { buf = (char *) realloc(buf, len + 1024); len += recv(client->fd, buf, 1024, 0); for (i = 0; i < len; i++) { if (buf[i] == '\n') break; } handle_msg(buf); rest = (char *) malloc(len - i); broadcast(client->id, buf, i + 1); free(buf); buf = rest; } }Pri oteviran isouboru je file descriptor z nejakeho duvodu NULL a ja netusim vubec proc.
Otvíráš jej pro zápis!, zkus se juknout do errno
.
valgrind
if((buff = realloc(buff,size)) == NULL){ ...chyba...a... }Když zklame už paměť neuvolníš, takže jedině v případě pokud následuje „bác“ (exit/abort), jinak něco jako:
void *tmp; if((tmp = realloc(buff,size)) == NULL){ ...chyba...a... free(buff);/*pokud to tedy neuvolnis nekde jinde*/ buff=NULL; return CHYBA; }else buff = (muj_typ*) tmp;
strcpy(home, buf);
nahradit: strncpy(home, buf, 1023); home[1023]='\0';
file = fopen(path, "rb");a v serverum kde ho chci vytvorit, ho oteviram pro (vytvoreni a)zapis:
FILE *fr = fopen(home, "wb");Co je na tom spatne?
strcpy
, ale jen memcpy
. Také je nesmysl přidávat nulu na konec, neboť tím zmršíš výsledný soubor. Musíš pracovat přímo s bufferem a vedle si uložit délku.
Přenos souboru udělej v cyklu. Načti 4KB do bufferu, zapamatuj si, kolik dat v bufferu skutečně je, a tyto dva parametry pak předej fwrite()
. Buffer si alokuj staticky na pevnou velikost. Dynamická alokace paměti je pomalá (proto se používají alokátory, které si od jádra alokují velký blok najednou a ten pak rozdávají dál).
Také ti to nebude fungovat s pojmenovanými rourami a soubory, do kterých se ještě stále zapisuje.
Dynamická alokace paměti je pomalá (proto se používají alokátory, které si od jádra alokují velký blok najednou a ten pak rozdávají dál).Jen pro zajímavost, díky jisté diskuzi zde, jsem si vytáhl staré zdrojáky a řekl jsem si že je upravím a něco zkusím (i když to nepotřebuji, ale vypadá to zajímavě nepotřebně, možná to pak hodím do blogu ;)), a při jedné úpravě mě opět překvapila, právě věc kolem toho co píšeš. Ve smyčkám rekurzivně jsem alokoval různě veliké bloky paměti (malé 8byte až ≈200B, v ø12-32byte)a to v řádu málo sekund i N-milionkrát, tak jsem si řekl, přesně to co píšeš, udělal jsem velmi jednoduchý alokátor. Ale i když provedl jen jednu alokaci celého bloku a nedělal nic jiného než testoval jestli má dost a posunoval counter (ukazatel), tak jsem byl na stejné rychlosti a při použití omp + critical dokonce na nižší, než při postupných alokacích, jediné co bylo rychlejší, tak free, ale spíš díky tomu, že při postupných alokacích jsem při free musel projít celý „strom“, kdežto že tady stačilo jen to free na celý blok.
-O0
(nebo-li -O
nezadáno) verzi skupinu s „floating“ nepatrně nejrychlejší s malloc (tedy roj malých alokací) a na herní konzole (i7/W7/cygwin) v této sekci dokonce poměr 1:4 ve prospěch malloc. Ostatní optimalizace, jsou v neprospěch malloc, nicméně jsou někdy v sekci floating nepatrné. Na i7, ze které píšu mám sekci floating vs -O0
v zásadě všechny hodnoty stejné a u -O1
a -O3
mi neodpovídají rozdíly bez floating a s floating (ztráta výkonu oproti malloc je s floating o kus nižší).valgrind
budeš rozhodně šťastnější s alokátorem (bude to mnohem rychlejší).
omp for
, tak tak nějak nechceš mít kontrolu nad jednotlivými thready), ale nejde o to, jde o to, že alokace velkého bloku a kontrola „máš dost“ + posunutí ukazatele při každém požadavku vs. alokace po drobcích vyšla na stejno (alokátor se provolával vždy, ale jednou udělal jen malloc a druhém případě alokoval na začátku a pak dělal to výše uvedené).
gcc -fopenmp -O1 test.c -std=c99Kód
#include "stdlib.h"
void* alloc1(int bytes) {
return malloc(bytes);
}
const int CHUNK_SIZE = 1024*1024;
void* alloc2(int bytes) {
static __thread void* alloc_start = 0;
static __thread void* alloc_end = 0;
static __thread void* alloc_ptr = 0;
if(alloc_start + bytes > alloc_end) {
void* new_buffer = malloc(CHUNK_SIZE);
*(void**)new_buffer = alloc_start; //previous allocated chunk
*(int *)(new_buffer + sizeof(void*)) = 0; //number of allocated substrings
alloc_start = new_buffer;
alloc_end = new_buffer + CHUNK_SIZE;
alloc_ptr = alloc_start + sizeof(void*) + sizeof(int);
}
void *ret = alloc_ptr;
alloc_ptr+=bytes;
return ret;
}
int main(void) {
#pragma omp parallel for
for(int r=0;r<1024*1024*200;r++)
alloc2(r % 21 * r % 13);
}
Ten test byl jen následný - pro zajímavost, ne to, co jsme popisoval jako první, to je moc komplexní, na jednoduchou prezentaci.
Implementace by mohla být krapet, lepší, ale zas tam chybí podstatná část, nalezení prvního volného bloku v jednotlivých chuncích, takto udělaný alokátor by hodně plýtval.
Přečetl jsi si i část Core2Duo, a taky to, že rozdíly při jednotlivých alokacích neodpovídali v sekce bez floating a s. Není důležité co dělá vlastní kód samostatně, ale co dělá v součinnosti s ostaním.
Nevytrhávej s kontextu, reagoval jsem na kontrétní větu, i s uvozením „OT“, kde jsem chtěl rozporovat obecnou informaci, že alokátor je vždy zásadním přínosem.
1. Znovu, pointa je v tom, že daná aplikace běží stejně rychle bez alokátoru, jak s alokátorem i bez omp. To že, s omp je/byla pomalejší s alokátorem který měl critical sekci je (asi) logické, ale zanést do aplikace jednotlivé alokátory pro jednotlivé thready by mělo nepříjemné side efecty se zbytky, takže by to nepřicházelo v úvahu. Celkem jistě by to pak nebylo pomalejší, nicméně obtížně implementovatelné a s nepříjemnými side efekty a pokud v aplikaci je i při milionech alokací (přes malloc) jejich vlastní čas zanedbatelný tak to stejně nic nepřinese.
2. Tvůj názor, můj je, že omp použiji jednoduše (a téměř výhradně tehdy pokud thready na sebe čekat nemusí), pokud je to složitější, řídím si thready a rozdělování úloh detailně já.
3. Nemám k tomu co říct.
4. Udělej si třeba nesmyslný, ale lepší(komplexnější) test a měř celkově strávený čas algortimu, ne jen alokaci navíc nepoužité paměti - to snad ani testovat nelze (nemá význam).
"Tuto zkušenost mám už opakovaně (C/C++ malloc/new), pokud jsou ty bloky moc malé a jedou rychle za sebou, tak na OS i herní konzole je to často stejně rychlá a někdy dokonce RYCHLEJŠÍ volba než alokátor,Samozřejmě může teď tvrdit, že když do vlastního alokátoru vrazíš sleep (něco podobnéhos defakto dělal, kdyžs to volal s O0), tak je určitě pomalejší, ale s odpuštěním když se porovnávají algoritmy, tak má smysl porovnávat pouze dobře napsané a stejně zoptimalizované algoritmy: a dobře napsaný custom alokátor je rychlejší než generický malloc. To můj test (a koneckonců i Tvůj) jasně prokázal. To, že když na každou alokaci přijde množství další práce Xkrát delší nežli trvá samotná alokace, tak je přínos v zrychlení alokace nevýrazný, je pravda, ale to je zaprve dosti jiné tvrzení než to, že malloc je rychlejší, jaks psal - a navíc tvrzení na úrovni věty "Kružnice je kulatá". V tom, že existují příklady, kdy opravdu vlastní alokátor význam nemá máš pravdu, ale sám Tvůj testovací (nefloating) kód, kde složitost nealokace odpovídá zpracování pomocí jednoduchého konečného automatu krásně ukazuje, že alokátor v případě, kdy je velká část programu složená z alokací, smysl rozhodně má. Totéž dokládá i Josef Kufner. A to jsou ty testy ještě navíc velmi příznivé pro malloc, protože se do těch alokací nemíchají alokace a dealokace jiných paměťových bloků, které zvětšují fragmentaci paměťového prostoru a zesložiťují mallocu vyhledávání volných bloků. 1b) Jaké nepřijemné sideefekty? Že se nedá dealokovat z jiného threadu? Dá se to napsat i tak, že si data s sebou nesou tag. kterým, threadem byly alokovaný a tak je lze dealokovat z jiného threadu, častý usecase je, že dealokaci provedu najednou po skončení práce (když zpracovávám dokument) pro všechny stringy najednou atd.... Jaký konkrétně sideefekt máš na mysli? 2) Tvůj názor Ti neberu, ale evidentně je s odpuštěním nepříliš užitečný, když evidentně Tě vede k tomu, že píšeš alokátor s omp critical, když lze totéž vyřešit Xkrát rychleji pomocí TLS. Právě genialita OpenMP je, že Ti nechávají volnost, co necháš vyřešit pomocí openMP automaticky a co budeš detailněji ladit (existují i direktivy omp parallel, které Ti nechávají větší volnost v tom, co thready dělají, existují funkce omp_get_thread_id atd...). Většinou je totiž problém skryt v nějakém detailu, který je snadno řeitelný vhodným SW návrhem a psát si kvůli tomu "vlastní OpenMP" je zbytečné. Nehledě na to, že za OpenMP je spousta práce a tak vlastní implementace bude zpravidla horší. 4) Tvrdil jsi:
Ale i když provedl jen jednu alokaci celého bloku a nedělal nic jiného než testoval jestli někdo má dost a posunoval counter (ukazatel), tak jsem byl na stejné rychlosti a při použití omp + critical dokonce na nižší, než při postupných alokacích,což můj testovací kód jednoznačně vyvrací - pokud nedělám nic, tak je custom alokátor dvakrát rychlejší, u paralelní verze je rozdíl ještě mnohem větší. Teda spíš než vyvrací Tvé tvrzení, tak spíš ukazuje na to, žes měl ten alokátor blbě napsaný. Pokud se bavíme o samotné užitečnosti custom alokátorů. tak má samozřejmě jediné, co má smysl testovat, je testovat pouze samotnou alokaci. Protože každý usecase toho alokátoru bude různý a tak nemá smysl říkat: "todle je standardní zátěž". Jediné, co tedy má smysl je změřit čas potřebný na jednu alokaci - to, jestli zlepšení v řádu např. desítek mikrosekund na jednu alokaci má v konkrétním případě smysl si pak přeci člověk snadno zjistí. Naopak pokud změřím čas zašpiněný nějakym mikrosleepem, tak vlastně nevím nic: protože v reálném použití může být objem té další práce řádově menší i větší než ten microsleep.
Ad 1. side-efect, je využití víc paměti než je ve výsledku třeba, a s jednotlivými thready se tento prostor zvětšuje.
Ad 2. Dělej si závěry jaké chceš, když si troufáš bez znalosti všech podmínek…, pokud budeš používat omp_get_thread_id apod. jistě víš, že to má také detail - režie.
Ad 4.„nedělal nic jiného“ = alokátor nedělal nic jiného něž to popsané(popis funkce alokátoru), zbytek kódu aplikace intenzivně pracoval (ono alokátor, tak nějak sám o sobě není na nic :)).
Pokud se bavíme o samotné užitečnosti custom alokátorů. tak má samozřejmě jediné, co má smysl testovat, je testovat pouze samotnou alokaci.Mám jiný názor, je sice dobré, že alokátor v holém testu vyleze super, ale hlavní je, jak se pak chová v součinnosti s celkem a na daném OS.
PS: Piš to kratší… ;)
1) Jak myslíš…, …aby měl alokátor smysl, je třeba alokovat po výrazně větších blocích a eliminovat počet fyzických alokací a pak v každém posledním alokovaném bloku zůstane relativně spousta nepoužité paměti a to je nežádoucí vedlejší efekt.
2a) No jasně, že neříkám všechno, protože kdyby to bylo triviální, tak ti sem ten k prdnu abych to nemusel vysvětlovat.
2b)Je malý, stejně jak může být malý zisk s využití alokátoru.
4) Možná ty se bavíš o principu, já od začátku prezentuji to k čemu jsem nedávno dospěl v konkrétním případě a tím jsem vyvracel obecný předpodklad, že alokátor vždy znamená zvýšení rychlosti.
Zjednodušeně, aby alokátor vždy znamenal přínos, museli bychom ignorovat, způsob fungování HV i OS, který nefunguje sériově, lineárně a bez vzájemných závislostí jednotlivých prvků, ano na Pentiu nebo 486 s adekvátním OS byl rozdíl až několika řádům s „předalokací“ a bez, ale ty rozdíly docela rychle mizí a možná za pár let se budou knihovní alokátory jen wraperry na malloc(low level alokaci) a třeba budeme mít k dispozici běžně terabajty paměti a budu moci konečně vyzkoušet některé nápady :), pišu tyto blafy taky proto, že mě to nebaví, já to tady vidím a nevadí mi to a ty voláš po jednoduché přesně dané jistotě.
"tuto zkušenost mám již opakovaně"generalizoval - sice ne explicitně, ale implicitně ano. 5) Malloc je knihovní funkce a většina jejího kódu běží v userspace. Její rychlost na OS tedy příliš nezávisí: závisí především na kvalitě libc knihovny, která může být přes různé OS stejná: např. glibc není problém provozovat na unixu, linuxu i BSD. Tvoje tvrzení by tak bylo možná pravdivé u velkých alokací dělaných pomocí přímého mapování fyzické paměti (mmap), ale tady se bavíme o malých alokacích a tam je to s prominutím prostě nepravda, v tomto případě nejvíce času nespotřebuje OS a systémová volání, ale userspace knihovní kód. Už vůbec netuším, jak by se v rychlosti malloc projevil jiný procesor - co konkrétně na staré 486 šlo při mallocu (relativně k rychlosti CPU) pomalu a na haswellu jde rychle? Malloc funguje defakto úplně stejně, jako custom alokátor: naalokuje od jádra OS velký kus paměti a ten pak po kouskách přiděluje jednotlivým voláním malloc. To, co dělá malloc složitým jsou dvě věci a) řešení fragmentace paměti, vyhledávání volného bloku atd... , b) mezithreadová synchronizace (týká se některých implementací mallocu, některé todle řeší). Pokud můžeš ušetřit na jedné z těchto věcí, pak se Ti hodí si napsat vlastní alokátor. Tj. pro případ A - např. pokud hodně alokuješ a chceš všechno uvolnit najednou, a případ B - pokud hodně alokuješ v různejch threadech a neceš si alokovaný věci mezi threadama půjčovat. Právě proto jsou Tvoje námitky proti custom alokátoru nesmyslný: psát vlastní alokátor s omp critical jde právě proti tomu, co můžeš vlastním alokátorem ušetřit. Stejně jako výtka, že ten jednoduchý alokátor neřeší fragmentaci paměti - on ji totiž neřeší úmyslně právě proto, že je jednoduchý a kdyby ji řešil, tak nemá smysl ho psát, protože malloc už napsaný je.
fd = fopen(path, "rb"); if (!fd) { fprintf(stderr, "Unable to open file %s", path); return; } fseek(fd, 0, SEEK_END); fileLen=ftell(fd); rewind(fd); fbuffer=(char *)malloc(fileLen); if (!fbuffer) { fprintf(stderr, "Memory error!"); fclose(fd); return; } while(!feof(fp)) { fread(fbuffer, 1, 1, fp); printf("%02x\n",byte); } result = fread (buffer,1,fileLen,fd); if (result != fileLen) { fputs ("Reading error",stderr); exit (3); }Soubor chci pote spojit s message pomoci memcpy (dle tve rady) takto:
char end[1]; end[0]= '\n'; fclose(fd); size_t len1 = strlen(message), len2 = strlen(fbuffer); char *concat = (char*) malloc(len1 + len2 + 2); memcpy(concat, buf, len1); memcpy(concat+len1, fbuffer, len2+1); memcpy(concat + strlen(concat), end, 1); send(sockfd, concat, strlen(concat), 0);Ale nevim jak docilit toho, aby se doubor nacetl korektne. Psal jsi o cyklu, tale to jsem pochopil, ze se to vztahuje az ke cteni prichoziho bufferu na serveru.
Fbuffer=(char *)malloc(FILELEN);
while(!feof(fP)) { fread(Fbuffer, 1, 1, fP); printf("%02x\n",byte); }
result = fread(?buffer,1,FILELEN,fD);Podle fileLen alokuješ fbuffer, ale do toho čteš z jiného descriptoru, než jsi si zjišťoval velikost a pak čteš do buffer, který nevím kde alokuješ.
void send_msg(char *message, char *path) { char msg[1024]; strcpy(msg, message); FILE * fr; long lSize; char * buffer; size_t result; char *header; fr = fopen(path, "rb"); if (fr == NULL) { fputs("File error", stderr); exit(1); } fseek(fr, 0, SEEK_END); lSize = ftell(fr); rewind(fr); buffer = (char*) malloc(sizeof (char)*lSize); if (buffer == NULL) { fputs("Memory error", stderr); exit(2); } result = fread(buffer, 1, lSize, fr); if (result != lSize) { fputs("Reading error", stderr); exit(3); } fclose(fr); size_t len1 = strlen(msg), len2 = strlen(buffer); /* delka zpravy */ asprintf(&header, "%d^", (int) len1 + (int) len2); printf("header is: %s\n", header); size_t len3 = strlen(header); char *concat = (char*) malloc(len1 + len2 + len3+1); if (concat == NULL) { MY_KILL_ON_ERROR("Concat message\n"); exit(1); } /* spoj vse dohromady */ memcpy(concat, header, len3); memcpy(concat + len3 , msg, len1); memcpy(concat+ len3 +len1, buffer, len2); send(sockfd, concat, strlen(concat), 0); free(buffer); free(message); free(header); message = NULL; }Tady jsou funkce serveru. thread_reader nacte buffer (zjisti si delku zpravy a souboru, nacte a posle do fce handle_msg ke zpracovani):
void handle_msg(char *buf, int buflen, int hdrlen) { char *p_str; char chunk[50000]; char home[1024]; char path[1024]; int j; int flag; int hm_len; int parlen; int is_dir; long fsize; /* delka souboru */ int meslen; int f, ofset; /*zkopiruj buffer do chunk pro ucely parsovani pomoci strtok*/ if (buflen < 1024) { memcpy(chunk, buf, buflen); f = 0; } else { memcpy(chunk, buf, 1024); buflen -= 1024; ofset = 1024; } while (f) { if (buflen < 1024) { memcpy(chunk + strlen(chunk), buf + ofset, buflen); fsize = 0; } else { memcpy(chunk + 1024, buf + ofset, 1024); buflen -= 1024; ofset += 1024; } } /* parsuj zpravu */ j = 0; p_str = strtok(chunk+hdrlen, ":"); while (p_str != NULL) { if (j == 0) flag = atoi(p_str); else if (j == 1) is_dir = atoi(p_str); else if (j == 2) hm_len = atoi(p_str); else if (j == 3) parlen = atoi(p_str); else if (j == 4) fsize = atol(p_str); else if (j == 5) strcpy(path, p_str); p_str = strtok(NULL, ":"); j++; } /* kontrolni vypisy */ printf("flag: %d\n", flag); printf("isdir: %d\n", is_dir); printf("hmlen: %d\n", hm_len); printf("parlen: %d\n", parlen); printf("fsize: %ld\n", fsize); printf("path: %s\n", path); /* nastav cestu do domovskeho adresare */ memset(home, '\0', strlen (home)); strcpy(home,mydir); strcat(home, path + hm_len); home[strlen(home)] = '\0'; char *parent = NULL; parent = get_parentdir(home); if ((flag == IN_CREATE) || (flag == IN_MOVED_TO) || (flag == IN_CLOSE_WRITE)) { mkpath(parent, S_IRWXU | S_IRWXG | S_IRWXO); if (is_dir) mkpath(home, S_IRWXU | S_IRWXG | S_IRWXO); else { FILE *fr = fopen(home, "wb"); if (fr == NULL) printf("File Cannot be opened file on server.\n"); /* vypocti delku bufferu pred daty */ meslen = (buflen - fsize) + hdrlen; /* zapisuj do souboru postupne po 1KB*/ if (fsize < 1024){ fwrite(buf + meslen, sizeof (char), fsize, fr); fsize = 0; } else { fwrite(buf + meslen, sizeof (char), 1024, fr); fsize -= 1024; meslen += 1024; } while (fsize) { if (fsize < 1024) { for (j = 0; j < fsize; j++) { fwrite(buf + meslen, sizeof (char), fsize, fr); meslen++; } fsize = 0; } else { fwrite(buf + meslen, sizeof (char), 1024, fr); fsize -= 1024; meslen += 1024; } } fclose(fr); } } free(parent); }Delal jsem vse podle vasich rad. Mam delku souboru, delku zpravy, zkopiruji prislusny pocet bajtu a poslu do fwrite. U malych souboru to funguje, u vetsich, treba kolem 10kB to nefunguje. Nevim proc a uz jsem z toho fakt zoufaly. 2) toto vse "funguje" v netbens debuggeru. Male soubory zkopiruje, vetsi zkopiruje, ale obsah je rozhazena zmet znaku. Kdyz ale debugger vypnu a spustim to normalne (nebo z prikazove radky) tak se nejenze nezkopiruje soubor, ale kontrolni vypisy promennych (flag, delka message, path) maji vzdy nulovou hodnotu. absolutnen etusim proc, setkal se s tom nekdy nekdo?
Zběžným pohledem len2 = strlen(buffer)
zjistí délku pro první '\0', takže binární filesi smůla jsou oříznuty (a mimochodem tu len2 už máš v result i lSize, jestli se dobře dívám).
Na handle_msg nemám fčul náladu :(.
while (fsize) { if (fsize < 1024) { fwrite(buf + meslen, sizeof (char), fsize, fr); fsize = 0; } else { fwrite(buf + meslen, sizeof (char), 1024, fr); fsize -= 1024; meslen += 1024; } }Problem to ovsem neresi stejne. A nemuzu poradne debugovat, kdyz mi v debuggeru neco jede, ale naostro neprochazi nic :( Sangala: dik aspon za tohle, to by u tech binarnich filu delalo problem (zatim zkousim jen na textovych).
void *thread_reader(void **_client) { client_t *client = *_client; char *buf = NULL; int meslen = 0; int len = 0; int i, j; char *rest; void *tmp; char *meschar; while (1) { if ((tmp = realloc(buf, len + 1024)) == NULL) { free(buf); buf = NULL; exit(1); } else buf = (char*) tmp; len += recv(client->fd, buf, 1024, 0); for (i = 0; i < len; i++) { /* zjisti delku zpravy */ if (buf[i] == '^'){ meschar = (char*)malloc (i-1); for(j = 0; j < i; j++){ meschar[j] = buf[j]; } meslen = atoi(meschar); j++; } if(i == (meslen + j)) break; } handle_msg(buf, meslen, j); rest = (char *) malloc(len - i); broadcast(client->id, buf, i + 1); free(buf); free(meschar); buf = rest; } } Problem je, ze bufer je vzdy pri vetsich souborech velky jen 1024 B. Takze posle prvnich 1024 do handle_msg a potom se provede dalsi loop a posle dalsich 1024.... Takze ted premyslim, jak to vyresit. Ted vecer uz asi nic nevymyslim, ale uvitam jakoukoliv radu.
int buffsize = 1024*1024; setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize));Cela fce tady:
void *thread_reader(void **_client) { client_t *client = *_client; int meslen = 0; int len = 0; int i, j; char *meschar; int buffsize = 1024*1024; setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buffsize, sizeof(buffsize)); char *buf; while (1) { buf = (char *) malloc(buffsize); if (buf == NULL) { free(buf); buf = NULL; exit(1); } len += recv(client->fd, buf, buffsize, 0); for (i = 0; i < len; i++) { /* zjisti delku zpravy */ if (buf[i] == '^'){ meschar = (char*)malloc (i-1); for(j = 0; j < i; j++){ meschar[j] = buf[j]; } meslen = atoi(meschar); j++; } if(i == (meslen + j)) break; } handle_msg(buf, meslen, j); broadcast(client->id, buf, i + 1); free(meschar); free(buf); } }A uz mi vetsi soubory prochazi, ale opet jen pri debugovani, kdyz si jedu v debuggeru krok za krokem. To mi vse krasne vypisuje, vsechny flagy:
flag: 8 isdir: 0 hmlen: 30 parlen: 30 fsize: 1655 path: /home/tomesh/Dropbox/C/dropbox/test home: /home/tomesh/Dropbox/C/sync/testJenze v ostrem rezimu (v netbeans nebo v prikazove radce) mi to vubec neprochazi:
flag: 0 isdir: 0 hmlen: 0 parlen: 0 fsize: 0 path: home: ./srvNevite nekdo cim by to mohlo byt?
Z toho, co jsem letmo přečetl z tvých zdrojáků: sizeof
operátor vrací hodnotu type size_t
. V C nemusíš přetypovávat z void* na ukazatel jiného typu, pouze v C++. Argument pro malloc je typu size_t
, né int
. Funkce recv
vrací ssize_t
, asi z nějakého důvodu (viz. man 2 recv
). sizeof(char)
je vždy 1
, nezávisle na tom, jestli má 8 nebo 125 bitů. Toto je potřeba vědět, než se posuneš dál.
Dále je potřeba vědět, že funkce typu recv
, read
, send
, ... nemusí přečíst/zapsat tolik bajtů, kolik po nich chceš. Ta hodnota určuje maximální počet bajtů, které zapíšou/přečtou. Kolik přečetly, ti řekne návratová hodnota. Může se ti vrátit i záporné číslo, např. když dojde k přerušení, když je plný buffer socketu, když nastane chyba, ...
while (1) { buf = (char *) malloc(buffsize); if (buf == NULL) { free(buf); // zbytečný, ale ok, free se s NULL vyrovná, spíše to ale říká, že nevíš, o co jde. buf = NULL; // opravdu? proč, když už víš, že tam NULL je exit(1); } len += recv(client->fd, buf, buffsize, 0); // A co záporné číslo?? for (i = 0; i < len; i++) { // opravdu?? A to jako, že ty bajty z recv vždy zapisuješ na začátek bufferu (a né na nějaký předchozí offset), prakticky čteš z bufferu kraviny, cos tam nikdy nezapsal. /* zjisti delku zpravy */ if (buf[i] == '^'){ // ... atd další věci, co už jsem líný komentovat, třeba že atoi předpokládá nulou ukončený řetězec }
Co ty potřebuješ, je ten protokol. Z toho, co jsem přečetl ze zdrojáku to vypadá, že tvůj protokol je něco jako:
VELIKOST_ZPRÁVY, číslo v ascii, ukončené znakem '^' ZPRÁVAZ tvého kódu soudím, že chceš mít celou zprávu načtenou v paměti, měl bys si tedy zvolit nějaké omezení velikosti zprávy. Pokud nepotřebuješ, můžeš si zvolit nějaký buffer, třeba ho i alokovat na zásobníku, a postupně ho zapisovat do souboru, jak načítáš data.
Dneska už jdu spát, jestli si pořád nebudeš vědět rady, více třeba zítra. Jsem ochotný ti napsat i kód, protože stejně nemám co dělat, všetně komentářů a vysvětlivek.
Tiskni
Sdílej: