[so] [Tema5] [LINUX] Transmitere fisiere static / dynamic

Adrian Stanciu adrian.stanciu.pub at gmail.com
Tue May 26 20:31:31 EEST 2015


2015-05-26 20:26 GMT+03:00 Adrian Stanciu <adrian.stanciu.pub at gmail.com>:
> 2015-05-26 19:17 GMT+03:00 Georgiana Diana <geodiana93 at gmail.com>:
>> Buna,
>> Eu tot am niste nelamuriri legate de citirea asincrona / trimiterea cu send
>> (inline):
>>
>
> Bună, Georgiana!
>
>> 2015-05-25 20:53 GMT+03:00 Adrian Stanciu via so <so at cursuri.cs.pub.ro>:
>>>
>>> 2015-05-25 20:49 GMT+03:00 Madalina Hristache via so
>>> <so at cursuri.cs.pub.ro>:
>>> > Salut,
>>>
>>> Bună, Mădălina!
>>>
>>> >
>>> > Am câteva nelămuriri și am nevoie de clarificarea lor ca să pot continua
>>> > tema.
>>> >
>>> > 1. Când transmitem un fișier din directorul static, trimitem header-ul
>>> > HTTP
>>> > cu send (non-blocant, asincron), apoi fișierul cu sendfile. Fără nicio
>>> > legătură cu libaio.h, da?
>>>
>>> Da, așa este.
>>>
>>> >
>>> > 2. Când transmitem un fișier din directorul dynamic, îl citim de pe disc
>>> > cu
>>> > apeluri legate de libaio.h, apoi îl punem pe socket. Și cum îl trimitem?
>>> > Cu
>>> > send? Sendfile? La partea asta sunt în ceață.
>>> >
>>>
>>> Cu send().
>>
>>
>> In exemplul din laborator [1], precum si in exemplul sugerat in tema [2]
>> (xmailserver), am observat ca se face read pe un file descriptor, pentru a
>> notifica serverul atunci cand operatia asincrona de citire s-a terminat.
>>
>> 1) Este acest read blocant, sau nu ?
>
> Acel read() pe eventfd este blocant, dar nu se va bloca dacă îl apelâm
> atunci când primim o notificare de la kernel, prin intermediul epoll.
>
>> 2) Care ar trebui sa fie workflow-ul server-ului in cazul trimiterii unui
>> fisier dinamic ? Ma gandeam ca unul posibil este acesta, dar inca nu imi dau
>> seama daca este corect:
>>
>> initializare io_context (in main, inainte de logica serverului);
>
> Este mai ușor dacă folosești un context IO per conexiune.
>
>> in server, primirea unui request de citire fisier dinamic;
>> trimiterea catre client a unui raspuns: 200/404, in functie de caz, prin
>> send-uri repetate (metoda comuna, atat pentru fisier static, cat si pentru
>> dinamic);
>> dupa trimiterea header-ului, in cazul unui fisier dinamic, serverul seteaza
>> un eventfd si submite un request de read pentru contextul aio -- actiune
>> neblocanta;
>> serverul face read pe eventfd-ul anterior -- actiune blocanta ?;
>
> Practic neblocantă dacă citirea se face la semnalizarea pe eventfd din
> partea epoll.
>
>> in urma notificarii de terminare a citirii din fisier a unui buffer in
>> general mai mic decat dimensiunea fisierului, serverul face apeluri send
>> repetate, pentru a trimite buffer-ul proaspat citit; -- in timpul acesta, se
>> presupune ca serverul initiaza o noua cerere de citire asincrona, sau
>> asteapta trimiterea buffer-ului curent ? ;
>
> E mai ușor dacă nu faci aceste operații simultan; e mai eficient dar
> ar trebui să tratezi în același timp mai multe tipuri de evenimente
> (read din fișier, send pe socket), care ar fi starea conexiunii? iar
> complexitatea implementării ar fi mai mare.
>
>> serverul continua sa citeasca bucati de fisier si sa le trimita catre
>> client.
>>
>> 3) Este corect ca in functia de trimitere fisier, pentru cazul unui fisier
>> dinamic, si care se tot apeleaza in bucla principala a server-ului (pentru
>> ca epoll este setat pe out, cat timp trimit un fisier), sa verific si sa
>> schimb starea conexiunilor (de ex, cat timp trimit fisierul, starea sa fie
>> SENDING_DATA, apoi, cand citirea asincrona se termina, pur si simplu sa
>> schimb starea in DATA_SENT si sa inchid conexiunea) ?
>
> Poți să:
> * activezi EPOLLIN pe eventfd pentru a aștepta finalizarea citirii
> asincrone a unei bucăți din fișier
> * planifici citirea asincronă a unei bucăți din fișier
> * activezi EPOLLOUT pe socket

Nu am spus complet aici ... activarea EPOLLOUT pe socket se face când
citirea asincronă a fost încheiată. Atunci avem date de trimis.

> * când ești notificată de epoll că poți să trimiți pe socket, trimiți
> bucata de fișier
> * dacă nu s-a trimis întreaga bucată mai aștepți un nou eveniment de
> EPOLLOUT pe socket din partea epoll și apoi trimiți ce ți-a mai rămas
> și tot așa
> * când ai terminat de trimis acea bucată, dezactivezi EPOLLOUT pe
> socket (căci deocamdată nu mai ai ce trimite)
> * o iei de la capât pentru a citi următoarea bucată din fișier
> * când ai trimis întreg fișierul se poate închide conexiunea
>


Adrian


More information about the so mailing list