Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Cum sterg mails din Promotions

Vanzare cumparare fara transfer b...

Receptie ciudata, in functie de t...

Dupa 20 ani de facultate, am uita...
 Mobile.de ofera imprumut de bani ...

problema test grila

Digi24 a disparut de pe TV Lg

Drept de proprietate intelectuala...
 Jante noi shitbox

Trinitas TV 4K

Dacia 1316 cu 6 usi ...

Frecventa modificata radio
 Un nou pericol pt batrani

Ar trebui sa vindem imobiliarele ...

Dupa renuntarea la aparat dentar

pelerinaj in Balcik
 

Dezvoltarea aplicațiilor ce comunică pe net

- - - - -
  • Please log in to reply
104 replies to this topic

#37
Gady_paul

Gady_paul

    Senior Member

  • Grup: Senior Members
  • Posts: 2,421
  • Înscris: 12.01.2008
Si lungimea cum o trimit? pe 2-3 caractere, apoi ii zic un atoi?

#38
edy_3dz

edy_3dz

    Rau sau bun

  • Grup: Senior Members
  • Posts: 3,241
  • Înscris: 30.08.2008
Direct ca si int, pe 8/16/32 de biti, cum alegi tu sau cat ai nevoie, big endian.

#39
Gady_paul

Gady_paul

    Senior Member

  • Grup: Senior Members
  • Posts: 2,421
  • Înscris: 12.01.2008
Bun, acum accepta mai multi clienti in paralel, si trimite numele fisierului. Mai am de rezolvat chestia aia cu zombie problem (trebuie sa mai sap putin, nu am experienta la multithreading deloc).

Acum intrebarea este: cum pot face serverul sa afiseze progresul la toti clientii? Chiar daca mi-a recomandat paullik un programel interesant, tinand cont ca inca invat, mai trebuie sa ma chinui putin cu reinventatul rotii Posted Image. In progress bar-ul meu, ma folosesc de /r, si periodic (de fiecare data cand este apelata functia mai exact), scriu un /r, ma duc la inceputul liniei si suprascriu caracterele. Acum serverul trebuie sa poata face asta pe mai multe randuri. No idea how...

Si ca era vorba de mutat pe windows...cat de minime pot fi schimbarile alea "minime", ca 80% din cod e cam...diferit Posted Image.

P.S. Link-ul e asta: https://github.com/P...tree/threading. Sa nu alergati prea mult dupa el Posted Image.
P.P.S. Momentan serverul sta deschis pana il inchid eu cu toporul (a se citi ctrl+c sau alte mijloace neortodoxe). Cum pot face ca el sa functioneze pana ii scriu exit de exemplu? stiu, as putea sa il intreb pe utilizator, numai ca pana raspunde utilizatorul serverul nu va primi conexiuni de la clienti.

Edited by Gady_paul, 20 July 2013 - 01:36.


#40
neagu_laurentiu

neagu_laurentiu

    Guru Member

  • Grup: Senior Members
  • Posts: 40,604
  • Înscris: 30.07.2003

View PostGady_paul, on 20 iulie 2013 - 01:30, said:

cum pot face serverul sa afiseze progresul la toti clientii?
Pentru modul text ai biblioteci cu ajutorul carora muti cursorul oriunde vrei in spatiul consolei (e o matrice de caractere pana la urma) si creezi cate un progress bar pentru fiecare. Daca a folosi o astfel de biblioteca pare greu atunci faci o treaba muncitoreasca, pe un singur fir de executie afisezi statusul la toti clientii conectati, fiecare pe un rand sa zicem. Acesta din urma culege sau primeste informatii de la restul firelor si se ocupa de afisare, sters ecran si iar afisare cu o pauza intre operatii de 200 ms (de ex.) sa nu omori procesorul incontinuu.

Edited by neagu_laurentiu, 20 July 2013 - 04:53.


#41
Paullik

Paullik

    Active Member

  • Grup: Members
  • Posts: 1,760
  • Înscris: 05.07.2008

View PostGady_paul, on 20 iulie 2013 - 01:30, said:

P.P.S. Momentan serverul sta deschis pana il inchid eu cu toporul (a se citi ctrl+c sau alte mijloace neortodoxe). Cum pot face ca el sa functioneze pana ii scriu exit de exemplu? stiu, as putea sa il intreb pe utilizator, numai ca pana raspunde utilizatorul serverul nu va primi conexiuni de la clienti.
Poti sa iei acel semnal (ca asta e defapt) si sa inchizi socketurile si fisierele cum trebuie cand este "raised", deci la CTRL+C tu poti face actiuni de cleanup, vezi SIGINT:
https://en.wikipedia...signal_handling

De asemenea vezi:
http://www.cplusplus...cstdlib/atexit/
Nu stiu excat daca terminarea procesului cu CTRL+C se incadreaza chiar la "program terminates normally", dar e bine de stiut ca exista functia asta.
Oricum, daca implementezi un signal handler pt. SIGINT nu o sa mai ai nevoie (in cazul asta) de functia atexit.

PS: Semi-solutii ar mai fi:
Rulezi server-ul propriu zis pe un thread (sau mai multe), iar pe thread-ul principal citesti de la tastatura, cand utilizatorul introduce "exit" sau CTRL+D (end of file) inchizi celelalte thread-uri, dar asta mi se pare asa... work-around, recomand solutia cu signal handlers.

Edited by Paullik, 20 July 2013 - 10:53.


#42
Gady_paul

Gady_paul

    Senior Member

  • Grup: Senior Members
  • Posts: 2,421
  • Înscris: 12.01.2008
Legat de afisarea simultana pe server al progresului fisierelor, nu e greu sa folosesc o biblioteca facuta pentru asta, dar, for learning purposes, as prefera sa o fac manual. M-am gandit ca serverul sa numere clientii, si fiecare thread din server care se ocupa cu transferul sa stie ca e al 5-lea de exemplu. Si functia care afiseaza loaderul, in loc sa afiseze un \r pentru a se duce la inceput, foloseste un escape sequence pentru a pune cursorul la inceputul liniei 5. Numai ca, la lansarea in executie a serverului ar trebui sa stiu pe ce linie se afla cursorul, pentru a putea calcula pe ce linie sta loaderul fiecarui fisier. Ma gandeam sa folosesc escape sequeces pentru a afla pe ce linie se afla cursorul, numai ca nu prea am reusit. stie cineva cum pot face asta?

Cat despre solutia cu signals, e o idee, dar asta ar insemna sa folosesc ctrl+c ca sa inchid executia. Eu ma gandeam ca utilizatorul sa poata folosi si alte mijloace de inchidere...mai...ortodoxe (nu prea am vazut programe care sa aiba ca singur mod de inchidere ctrl+c). semi-solutia de acolo ar fi plauzibila (combinata si cu signals eventual). Alte idei?

#43
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007
Daemon-urile sub Linux nici n-au interfata deregula, asa ca oricum nu sta utilizatorul sa scrie EXIT in ele :P

#44
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007
Avand in vedere ca unii au cam reusit sa creeze un server, propun urmatoarea tema pentru a face trecerea spre dezvoltarea site-urilor.

Tema

Sa se realizeze un server HTTP 1.0.
  • Acesta va servi static toate fisierele dintr-un anume folder.
    Daca browser-ul cere /index.html, el va primi continutul fisierlui D:\site\index.html.
    Daca browser-ul cere /, el va primi o lista cu toate fisierele din acel director.
  • Acesta va servi dinamic pagina /patrat
    Daca browser-ul cere /patrat si transmite prin GET parametrul numeric a, browser-ul va primi drept raspuns patratul numarului a

    • GET /patrat?a=2 HTTP/1.0
      => <html>Patratul lui 2 este 4</html>
    • GET /patrat?a=Ion HTTP/1.0
      => <html>Eroare, a trebuie sa fie un numar</html>

  • Acesta va servi dinamic paginile /login respectiv /verifica
    Daca utilizatorul acceseaza /login pentru prima data, acestuia ii va fi afisat un formulat de login (utilizator & parola) ce foloseste POST (tot spre /login).
    Daca introduce Ion respectiv 1234, utilizatorul primeste mesajul Login OK, altfel Login esuat.
    Daca utilizatorul intra pe /verifica, browserul ii va afisa daca este autentificat sau nu. Pentru asta, server-ul va trebui sa activeze un cookie in momentul autentificarii lui Ion, si sa-l verifice cand utilizatorul cere pagina /verifica

Aplicatia va fi usor de testat folosind orice browser.
Pentru partea statica, creati ceva site mic format din cateva fisiere html si cateva poze.

STATIC - browserul cere o resursa (ex, /index.html), serverul considera ca e vorba de pe un fisier de pe disc, iar daca acesta exista, e citit iar continutul sau trimis mai departe catre client
DINAMIC - browserul cere o resursa adesea oferind si informatii suplimentare (ex. /patrat?a=2), serverul considera ca e vorba de o aplicatie, executa aplicatia in cauza (daca exista) trimitandu-i ca date de intrare, informatiile precizate, iar apoi trimite spre client raspunsul aplicatiei.

In cazul cerintelor din aceasta tema, aplicatiile pentru /patrat, /login, /verificare nu vor fi executabile separate, ci codul lor va fi implementat direct in server (ex. functia patrat(...) va fi apelata daca clientul cere /patrat).

Beneficiile temei

  • Exersati temeinic procesarea sirurilor de caractere, cu o utilitate foarte practica
  • Exersati crearea unui server folosind un protocol cunoscut deja. Se poate usor testa, daca incepe browser-ul sa afiseze balarii, va dati usor seama ca ceva nu e ok
  • Intelegeti ce inseamna o pagina web statica
  • Intelegeti ce inseamna o pagina web dinamica si unde e executat codul ce o face dinamica.

Daca reuseste cineva asta, va arat cum puteti introduce PHP in poveste.

#45
Paullik

Paullik

    Active Member

  • Grup: Members
  • Posts: 1,760
  • Înscris: 05.07.2008
Hehe, aveam de ceva timp pe todo list "create a simple HTTP server", numa' bine!

Am trisat putin, am folosit Qt si C++, nu C, din diverse motive.
https://github.com/paullik/http-daemon

Codul e plin de TODOs, dar face tot ce a spus dani.user mai sus.

Pareri si critici, va rog!

In mare parte as vrea sa-mi spuneti daca e ok dpdv arhitectural si structural.

Apoi nu stiu exact cum sa fac citirea in cazul unei cereri POST daca nu este trimisa dintr-o bucata pe retea, sa zicem ca se trimite asa:
POST /foo HTTP/1.1\r\n
Content-Length: 3\r\n
\r\n


Prima bucata, apoi:
n=2

Asta e o cerere POST valida, doar ca e trimisa in doua bucati, in codul meu s-ar opri dupa field-urile din header (cele doua secvente CRLF) si nu ar mai citi body-ul.
Am o idee in minte, dar mi se pare destul de complicata si ma intreb cum ati rezolva voi problema asta.

As citi pana gasesc cele doua secvente CRLF si apoi as parsa request header-ul ca sa aflu din Content-Length cat mai trebuie citit si as continua cu citirea body-ului, dar poate cand am citit am sarit deja peste CRLF-urile alea si ar trebui sa ma uit inapoi ca sa vad cat de mult am citit peste ele si sa citesc doar cat a ramas. Aici mi se pare ca se complica inutil codul si ma gandesc ca poate voi aveti ceva idei mai bune/simple. Problema asta se vede cand fac cererile cu telnet

De asemenea ma deranjeaza tare de tot metodele check(), login() si square() ca nu-si au locul in clasa HTTPThread, daca era dupa mine as fi facut o clasa ModuleLoader si as fi incarcat functionalitatea (data acum de acele metode) din .so-uri sau .dll-uri cu un mic dictionar de configurare gen:
"requested_path" -> "module_to_load.so"

Nu m-am aruncat la implementarea incarcarii unor astfel de module ca nu stiu exact cum se face integrarea diferitelor tehnologii (PHP si Python am in minte) si am zis ca poate o sa impusc doi iepuri dintr-o data. Stiu ca pt. PHP in apache pot folosi mod_php.so, in lighthttpd FastCGI, iar pt. Python stiu de WSGI, dar nu stiu exact ce-s astea si de unde sa incep ca sa o iau cu inceputul...

@dani.user, tine-o tot asa.

Edited by Paullik, 23 July 2013 - 19:56.


#46
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007
Nu stii niciodata din cate bucati vei primi datele.

Faci un buffer mai mare (eventual dinamic sau cu verificari sa nu poata fi exploatat vreun buffer overflow) si bagi in el tot ce vine, verificand constant daca in buffer exista un \n\n (\r nu e obligatoriu). Daca ai intalnit (\r)\n(\r)\n, extragi frumos headerul din bufferul acela si-l parsezi. Daca, dupa ce-ai analizat headerul te intereseaza si ce-i dupa \n\n, iei din bufferul actual ce-o mai ramas dupa \n\n si dai mai departe spre procesare, urmand sa dai mai departe spre procesare si ce primesti in continuare pe socket, fara a mai baga in acel buffer.

Pe Content-length iar nu te poti baza tot timpul, acesta putand lipsi, caz in care citesti pana la inchiderea conexiunii.

Apoi, foloseste HTTP 1.0 pentru inceput, scapi de niste batai de cap.

Integrarea cu PHP o voi prezenta pe weekend, mai las ceva timp si altora sa incerce sa vina cu o solutie.

Observatii

  • Arhitectura
    • E departe de o solutie OOP, dar nu asta era scopul exercitiului
    • Dupa ce incepi sa citesti "de pe fir", nu mai e mai nimic OOP in design, in afara de faptul ca folosesti clase din framework
  • Qt
    • Daca folosesti signals & slots pentru QTcpServer, de ce nu faci la fel si pentru socket-uri?
      [ https://www.youtube-nocookie.com/embed/j9uAfTAZrdM?feature=oembed - Pentru incarcare in pagina (embed) Click aici ]
    • Metoda de servire a fisierelor statice e cam ineficienta. Practic incarci tot fisierul in memorie si tot concatenezi array-uri, cand ai putea sa trimiti direct pe tava pe masura ce citesti.
  • HTTP
    • Cookie-ul acela nu-mi place deloc. Practic, utilizatorul poate zice din prima ca e autentificat, iar tu o iei de buna :). Cauta o solutie pentru ca acel cookie sa nu poata fi ghicit de cineva, iar pe baza lui sa stii ca Ion a accesat pagina de verificare


#47
Paullik

Paullik

    Active Member

  • Grup: Members
  • Posts: 1,760
  • Înscris: 05.07.2008

View Postdani.user, on 23 iulie 2013 - 21:33, said:

Pe Content-length iar nu te poti baza tot timpul, acesta putand lipsi, caz in care citesti pana la inchiderea conexiunii.
Standardul zice ca ar trebui sa retrnez 400 Bad request daca nu am Content-Length si exista un body, asa am si refacut, daca cererea e POST si nu am Content-Length, eroare, altfel ma orientez dupa Content-Length.

Dupa inchiderea conexiunii nu ma pot orienta oricum, deoarece clientul tine conexiunea deschisa asteaptand de la server raspunsul.

View Postdani.user, on 23 iulie 2013 - 21:33, said:

Integrarea cu PHP o voi prezenta pe weekend, mai las ceva timp si altora sa incerce sa vina cu o solutie.
OK, niste pointeri ca sa citesc despre asta pana atunci, niste termeni tehnici care au legatura cu ce vei zice?
Nu de alta, dar eu in weekend plec si o sa fie o pauza, si vreau sa am sapt. asta de lucru.

View Postdani.user, on 23 iulie 2013 - 21:33, said:

  • Arhitectura
    • E departe de o solutie OOP, dar nu asta era scopul exercitiului
    • Dupa ce incepi sa citesti "de pe fir", nu mai e mai nimic OOP in design, in afara de faptul ca folosesti clase din framework
Recomanda-mi ce-i de facut, te rog!

View Postdani.user, on 23 iulie 2013 - 21:33, said:

  • Qt
    • Daca folosesti signals & slots pentru QTcpServer, de ce nu faci la fel si pentru socket-uri?
Done, initial ma gandisem ca oricum sunt pe thread si pot sa folosesc metodele blocking.

View Postdani.user, on 23 iulie 2013 - 21:33, said:


    • Metoda de servire a fisierelor statice e cam ineficienta. Practic incarci tot fisierul in memorie si tot concatenezi array-uri, cand ai putea sa trimiti direct pe tava pe masura ce citesti.
Will do.

View Postdani.user, on 23 iulie 2013 - 21:33, said:

  • HTTP
    • Cookie-ul acela nu-mi place deloc. Practic, utilizatorul poate zice din prima ca e autentificat, iar tu o iei de buna Posted Image. Cauta o solutie pentru ca acel cookie sa nu poata fi ghicit de cineva, iar pe baza lui sa stii ca Ion a accesat pagina de verificare
Mda, nu m-am axat prea tare pe acea parte deoarece am vrut sa pun accentul pe core-ul daemonului, ca ala nu se schimba, partea dinamica e treaba celui ce scrie aplicatii web.
In mod normal as genera un id format din nick si ceva random data , id pe care l-as stoca in db si in cookie, iar cand userul vine pe server cu cookie-ul respectiv eu verific ca id-ul sa fie cel aferent lui din db.

#48
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007

View PostPaullik, on 24 iulie 2013 - 12:38, said:

Standardul zice ca ar trebui sa retrnez 400 Bad request daca nu am Content-Length si exista un body, asa am si refacut, daca cererea e POST si nu am Content-Length, eroare, altfel ma orientez dupa Content-Length.

Dupa inchiderea conexiunii nu ma pot orienta oricum, deoarece clientul tine conexiunea deschisa asteaptand de la server raspunsul.

Corect, ma gandeam invers, la ce trimite serverul.

View PostPaullik, on 24 iulie 2013 - 12:38, said:

OK, niste pointeri ca sa citesc despre asta pana atunci, niste termeni tehnici care au legatura cu ce vei zice?

http://stackoverflow...stom-web-server

View PostPaullik, on 24 iulie 2013 - 12:38, said:

Recomanda-mi ce-i de facut, te rog!

De exemplu

  • Creezi doua clase model, HTTPRequest, HTTPResponse ce contin informatiile primite/de trimis catre client. De exemplu metoda, versiunea, content length, cookie-uri, etc. Query-ul, de exemplu ar fi stocat frumos sub forma de perechi cheie-valoare. Cele doua clase ar contine si cate un stream pentru citire respectiv scriere.
  • Creezi o clasa HTTPRequestParser ce ar avea rolul de a citi informatiile primite prin socket si de a crea o clasa HTTPRequest corespunzatoare. Stream-ul la care va face referire aceasta clase va permite citirea ulterioara a informatiilor in cazul unui POST de exemplu.
  • Dupa ce ai obtinut un HTTPRequest, il dai mai departe catre o instanta a unei noi clase, sa-i zicem Dispatcher, ce verifica ce este cerut defapt si, pe baza unor reguli, returneaza o referinta spre un HTTPRequestHandler.
  • HTTPRequestHandler-ul ales va primi apoi cererea si va returna un raspuns, HTTPResponse. Din stream-ul mentionat in acesta, se vor citi datele pe care serverul le va trimite inapoi, spre client.
  • Exemple de HTTPRequestHandler ar fi FileHTTPRequestHandler ce serveste static un fisier aflat pe disc, sau diverse clase ce ar reprezenta aplicatii custom gen cea necesara pentru /patrat. Astfel de aplicatii ar putea fi stocate si in DLL-uri, ele fiind destul de independente. Treaba lor ar fi astfel doar de a returna un raspuns la o cerere, neinteresandu-le cum citesti tu din socket, sau cum gestionezi 1000 de conexiuni simultane.

View PostPaullik, on 24 iulie 2013 - 12:38, said:

In mod normal as genera un id format din nick si ceva random data , id pe care l-as stoca in db si in cookie, iar cand userul vine pe server cu cookie-ul respectiv eu verific ca id-ul sa fie cel aferent lui din db.

Aici poti tine chiar in memorie acele informatii. Scapi de multe situatii unde folosirea bazelor de date (primul lucru care-ti trece prin minte cand folosesti php) e overhead.

#49
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007
Gady_paul, te incumenti sa rezolvi tema cu serverul web?

#50
Gady_paul

Gady_paul

    Senior Member

  • Grup: Senior Members
  • Posts: 2,421
  • Înscris: 12.01.2008
Vine si ea :D. M-am mai chinuit putin cu vechea tema sa o mai finisez (fara prea mari succese).

#51
Gady_paul

Gady_paul

    Senior Member

  • Grup: Senior Members
  • Posts: 2,421
  • Înscris: 12.01.2008
ok, gata. I-a venit randu :D

Da' au venit si problemele, asa ca o sa am nevoie de oleaca de ajutor.
Eu m-am gandit sa fac asa: fac un buffer de 1000 de bucati (sper ca ajunge) si iau caracter cu caracter si bag in el. numai ca dupa sapaturi indelungi, am aflat ca la el liniile se termina in "\v\n" (parca \v e escape de la vertical tab), nu in "\n\n". o iau eu razna sau asa e?

#52
Paullik

Paullik

    Active Member

  • Grup: Members
  • Posts: 1,760
  • Înscris: 05.07.2008

View PostGady_paul, on 19 august 2013 - 20:27, said:

ok, gata. I-a venit randu Posted Image

Da' au venit si problemele, asa ca o sa am nevoie de oleaca de ajutor.
Eu m-am gandit sa fac asa: fac un buffer de 1000 de bucati (sper ca ajunge) si iau caracter cu caracter si bag in el. numai ca dupa sapaturi indelungi, am aflat ca la el liniile se termina in "\v\n" (parca \v e escape de la vertical tab), nu in "\n\n". o iau eu razna sau asa e?
\r\n

Dar nu te baza pe asta, fa initial asa, dar cineva poate trimite si doar "\n"-uri pt. separare, totusi ca tema, merge si doar cu "\r\n".
Buffer-ul il redimensionezi daca nu-ti ajunge, dar nu faci redimensionarea cu cate un caracter sau ceva mic, ca risti sa fie incet daemonul, aloci blocuri de memorie ca sa eviti apelarea malloc/realloc de multe ori.

Spor!

#53
OriginalCopy

OriginalCopy

    I'm harmful, fear me please! :))

  • Grup: Senior Members
  • Posts: 27,268
  • Înscris: 10.08.2006

View PostGady_paul, on 16 iulie 2013 - 10:15, said:

Mi-am facut si eu tema...oarecum Posted Image. Am realizat o aplicatie ce transfera fisiere de colo colo. Inca mai am putin de lucru la ea (chestii gen erori, mesaje, eventual sa fie o aplicatie comuna ce poate rula si ca server si ca client, etc) dar functionalitatea de baza e la locul ei. E linux-only. Deci, pareri?
Error handling acela e over-engineered si nici nu face ceva ce poate deveni util in viitor. Mai curat ar fi niste #define cu constantele string si un macro de genul

#if 1
# define ERR_LOG(fmt, args...) fprintf(stderr, "%s (%d) in %s(): ", \
	__FILE__, __LINE__, __FUNCTION__); \
	fprintf(stderr, fmt, ## args)
#else
# define ERR_LOG(fmt, args...)
#endif



#54
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,239
  • Înscris: 24.02.2007

View PostGady_paul, on 19 august 2013 - 20:27, said:

Eu m-am gandit sa fac asa: fac un buffer de 1000 de bucati (sper ca ajunge) si iau caracter cu caracter si bag in el. numai ca dupa sapaturi indelungi, am aflat ca la el liniile se termina in "\v\n" (parca \v e escape de la vertical tab), nu in "\n\n". o iau eu razna sau asa e?

Pur si simplu ignori acel \r si obtii acelasi numaru de linii si daca sunt separate de \r\n si daca sunt separate de \n

Anunturi

Chirurgia cranio-cerebrală minim invazivă Chirurgia cranio-cerebrală minim invazivă

Tehnicile minim invazive impun utilizarea unei tehnologii ultramoderne.

Endoscoapele operatorii de diverse tipuri, microscopul operator dedicat, neuronavigația, neuroelectrofiziologia, tehnicile avansate de anestezie, chirurgia cu pacientul treaz reprezintă armamentarium fără de care neurochirurgia prin "gaura cheii" nu ar fi posibilă. Folosind tehnicile de mai sus, tratăm un spectru larg de patologii cranio-cerebrale.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate