Internet Info, s.r.o. Lupa Root Měšec Podnikatel DigiZone Slunečnice Vitalianew Bomba Navrcholu Weblogy Jagg Woko Dobrý web Computer.cz SK: MojeLinky

Hlavní navigace

Sokety a C/C++: Funkce select

V minulém dílu jsme si ukázali, jak seskupit sokety do množiny. Nyní si předvedeme, k čemu je množina soketů dobrá.

Pro práci s více sokety najednou slouží funkce select. Funkce select je schopna pracovat se třemi skupinami soketů. V první skupině hlídá, zda v některém soketu nejsou příchozí data, která je možno číst. Ve druhé skupině hlídá, zda do některého soketu je možné data zapisovat. Sokety ve třetí skupině jsou kontrolovány, zda se nenacházejí v chybovém stavu.

Funkce select v Linuxu

V množinách, které jsou předávány funkcí select jako parametry, jsou celá čísla, která mohou představovat jakýkoliv identifikátor souboru (file descriptor). Protože tento seriál je zaměřen na sokety, budeme dále hovořit pouze o soketech. Funkce select je ale obecnější. Například v manuálových stránkách select je uveden příklad použití funkce select se standardním vstupem.

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

 – druhý parametr je ukazatel na množinu obsahující sokety (obecně jakékoliv file descriptory), z nichž chceme číst. Třetím parametrem je ukazatel na množinu soketů (obecně jakýchkoliv file descriptorů), do kterých chceme zapisovat. Čtvrtým parametrem je ukazatel na množinu soketů (obecně jakýchkoliv file descriptorů), u kterých chceme zjistit, zda nastala nějaká chyba. Ve třech množinách jsou vlastně celá čísla. Vezmeme nejvyšší z těchto čísel, zvýšíme ho o 1 a máme číslo, které předáme jako první parametr. Posledním parametrem je ukazatel na strukturu udávající, jak dlouho má funkce select tento dohled provádět. Funkce vrací –1 v případě chyby. Jinak vrací počet soketů, na nichž došlo k událostem, které mají být sledovány. V případě, že vyprší časový limit daný posledním parametrem, funkce select vrací 0, protože počet soketů na kterých došlo ke změně, je 0.

Funkce select v MS Windows Ž

V množinách, které jsou předávány funkcí select jako parametry, jsou celá čísla, jež mohou představovat POUZE soket. Zde je velký rozdíl oproti unixovým systémům.

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout); – prvním parametrem je jakékoliv celé číslo. Parametr je zde pouze z důvodu kompatibility s klasickým soketovým rozhraním. V dokumentaci je přímo napsáno, že prvním parametrem může být jakékoliv číslo. A je to pravda. Zkoušel jsem zadat 0 (což by v klasickém soketovém API určitě nešlo) a vše fungovalo tak, jak má. Druhý parametr je ukazatel na množinu obsahující sokety, z nichž chceme číst. Třetím parametrem je ukazatel na množinu soketů, do kterých chceme zapisovat. Čtvrtým parametrem je ukazatel na množinu soketů, u kterých chceme zjistit, zda nastala nějaká chyba. Posledním parametrem je ukazatel na strukturu udávající, jak dlouho má funkce select tento dohled provádět. Funkce vrací hodnotu makra SOCKET_ERROR v případě chyby. Jinak vrací počet soketů, na nichž došlo k událostem, které mají být sledovány. V případě, že vyprší časový limit daný posledním parametrem, funkce select vrací 0, protože počet soketů, na kterých došlo ke změně je 0.

Jak vlastně s funkcí select pracovat?

Nejprve musíme zaplnit tři množiny podle toho, jaké události chceme sledovat. Vlastně nám stačí zaplnit jen jednu. Místo dalších můžeme předat NULL. Poté zavoláme funkci select. Funkce zablokuje chod programu a čeká, dokud nenastane nějaká sledovaná událost na soketech. Je-li posledním parametrem NULL, funkce čeká, dokud doopravdy k události nedojde. Je-li jako poslední parametr předán ukazatel na strukturu s časovým údajem, funkce čeká, dokud nenastane nějaká požadovaná událost na soketech nebo dokud nevyprší časový limit. Po skončení volání funkce select zjistíme z návratové hodnoty, zda došlo k chybě nebo na kolika soketech se událo něco rozhodujícího. Každá ze tří množin obsahuje po skončení volání funkce select jen ty sokety, na kterých nastala požadovaná událost. Nikdy nesmíme zapomenout, že nemuselo dojít pouze ke změně na jednom soketu.

My budeme používat asi nejvíce první množinu (druhý parametr funkce select). Funkce nám pohlídá, zda na soketech v této množině jsou k dispozici nějaká data, zda na soket přišel požadavek na spojení nebo zda druhá strana spojení přerušila. Zjistíme vlastně, na které sokety můžeme v blokovacím režimu zavolat recv nebo accept a přitom mít jistotu, že tyto funkce nebudou na nic čekat.

Ukázkový kousek zdrojového textu

// Struktura s časovým limitem
timeval tv;
// Množina
fd_set myset;
// Množina obsahuje náhodná data. Odstraním je.
FD_ZERO(&myset);
// Zaplnění množiny sokety
FD_SET(socket, &myset);
FD_SET(jinySocket, &myset);
// Vyplním časový údaj (například na 3 minuty)
tv.tv_sec = 180;// Počet sekund
tv.tv_usec = 0;// Počet mikrosekund
// Zavolám select (V Linuxu musím mít nastavenou proměnnou max.)
int ret = select(max, &myset, NULL, NULL, &tv);
if (ret == -1)
{
  // Nastala chyba
}
if (ret == 0)
{
  // Vypršel časový limit
}
if (FD_ISSET(soket, &myset))
{
  /* Obsluha soketu. Zde je možné vytvořit nové vlákno nebo proces,
který obslouží událost na soketu. Server pak je vícevláknový.
*/
}
if (FD_ISSET(jinySoket, &myset))
{
  /* Obsluha soketu. Zde je možné vytvořit nové vlákno nebo proces,
který obslouží událost na soketu. Server pak je vícevláknový.
*/
}

Příklad serveru

Jako ilustrační příklad si předvedeme jednoduchý server, který bude čekat na TCP portu číslo 2902 na spojení. V případě navázání spojení bude s klientem komunikovat tak dlouho, dokud klient neuzavře spojení. Nebude-li se serverem tři minuty nikdo komunikovat, uzavře všechna spojení a ukončí se. Server očekává, že mu jednotliví klienti posílají text. Text, který server obdrží od jednoho klienta, bude rozeslán všem klientům. Jedná se vlastně o velice jednoduchý chat server. K serveru se lze připojit například telnetem nebo si můžete sami naprogramovat jednoduchého klienta na základě článku TCP klient v Linuxu.

V programu používám šablonu vector a standardní algoritmus for_each. Server je jednovláknový. Mohli bychom například pomocí fork vytvořit nový proces pokaždé, kdy by server obdržel data. S paralelismem ale přicházejí problémy se synchronizací. Tématem seriálu jsou sokety, proto se synchronizací zabývat nebudeme.

Tabulka č. 437
Soubor OS
lin13.tgz Linux
win13.zip MS Windows Ž

Příště se podíváme na práci se sokety v neblokovacím režimu.

Školení unit testování v PHP

Akademie Root
  • Naučte se psát kód, kterým předejdete většině chyb už při vývoji.
  • Získejte spustitelnou dokumentaci kódu a usnadněte začleňování práce nových kolegů.
  • Postupy školené Jiřím Kneslem šetří čas při hledání chyb!
  • Psaní testů vás bude bavit!

Detailní informace o kurzu...

Ohodnoťte jako ve škole: 12345
Průměrná známka 3,15

Přehled názorů

bez titulku
lzap 2. 6. 2003 09:46
└ 
Re:
Radim Dostál 2. 6. 2003 10:14
 
├ 
Re: cpp2html
mol 2. 6. 2003 11:09
 
└ 
Re:
Michal Eibl 2. 6. 2003 11:57
 
 
├ 
Re:
martin hassman 2. 6. 2003 12:26
 
 
└ 
Re:
Radim Dostál 2. 6. 2003 23:35
 
 
 
└ 
Re:
Michal Eibl 3. 6. 2003 21:51
Jak je to s tim selectem?
Tygrik 2. 6. 2003 14:51
├ 
Re: Jak je to s tim selectem?
sss 2. 6. 2003 18:10
│
└ 
Re: Jak je to s tim selectem?
Tygrik 2. 6. 2003 19:14
└ 
Re: Jak je to s tim selectem?
Radim Dostál 2. 6. 2003 23:29
Peníze nesmrdí?!!
u_x 2. 6. 2003 18:51
co dal ?
sd 2. 6. 2003 19:02
├ 
Re: co dal ?
kokot 2. 6. 2003 21:22
└ 
Re: co dal ?
Radim Dostál 2. 6. 2003 23:44
off topic: co ta reklama
tomas 2. 6. 2003 19:12
C++
Ondrej Svetlik 4. 6. 2003 10:29
└ 
Re: C++
Radim Dostál 4. 6. 2003 21:14
 
└ 
Re: C++
Ondrej Svetlik 9. 6. 2003 12:03
dotaz
Jan Spurny 11. 6. 2003 14:29
└ 
Re: dotaz
Radim Dostál 13. 6. 2003 14:44
ACCEPT
jobo 3. 10. 2003 09:03
└ 
Re: ACCEPT
jobo 8. 10. 2003 09:17
Problem :(
anonymní uživatel 27. 8. 2005 18:13
! Prosím pomoc !
ZeXx86 7. 2. 2006 13:07
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem