Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
C/C++
Zpracování chyb soketů v Linuxu
cpp net
7. března 2003, 00.00 | Článek se zabývá způsobem jak identifikovat a ošetřit chyby soketů. Informace z článku lze využít v mnoha případech, nejen při práci se sokety. Podíváme se na proměnné errno a h_errno. Dále se budeme zabývat funkcemi pro práci s těmito proměnnýmy. Zejména se jedná o funkce perror, strerror a herror.
Dnes se podíváme na způsob identifikace a zpracování chyb soketů v operačním systému Linux. V mých článcích jsem dodnes popsal mnoho soketových funkcí. Vždy jsem upozornil jak poznat, že funkce proběhla bez chyb. Většinou se jedná o přečtení návratové hodnoty funkce, která nám oznámila, jestli operace proběhla bez chyby nebo s chybou. Například jsem napsal, že funkce gethostbyname vrací v případě chyby NULL. Nebo funkce connect vrací v případě chyby -1. Nám ale mnohdy nestačí zjistit, že došlo k chybě. Zajímá nás ještě k jaké chybě došlo. V operačním systému Linux existuje obecný mechanizmus pro zjišťování chyb při volání knihovních funkcí. Vše se točí kolem externí proměnné errno. Mechanizmus, který si zde popíšeme je použitelný pro jakékoliv funkce standardní knihovny nebo knihovních funkcí jádra. Můžeme dokonce do proměnné errno ve svých funkcích zapisovat. Proměnná errno se používá velice často. Přesto jsem zjistil, že například funkce gethostbyname (a další funkce pro práci s DNS) ji nepoužívá. Místo ní používá rovněž externí proměnnou h_errno. Princip práce s h_errno je velmi podobný principu práce s errno.
Externí proměnná errnoChceme-li používat proměnnou errno, musíme vložit (include) hlavičkový soubor errno.h. Ve svém programu deklarujeme proměnnou errno s modifikátorem extern. Pro úplnost připomínám, že tento modifikátor nám (a hlavně linkeru) oznamuje, že proměnná je ve skutečnosti deklarována v jiném modulu a my jí chceme používat. Budeme ji tedy vlastně sdílet s jiným modulem. Proměnná errno je typu int. Takže deklarace vypadá takto:
extern int errno;
Jestliže zavoláme nějakou funkci, která nám pomocí své návratové hodnoty sdělí, že došlo k chybě, je proměnná errno naplněná kódem vzniklé chyby. V dokumentaci k jednotlivým funkcím máme vždy napsáno k jakým chybám může dojít. Kódy chyb jsou většinou reprezentovány jako makra. Tyto makra jsou většinou deklarována v hlavičkovém souboru errno.h. Podívejme se například na funkci send. V manuálových stránkách funkce send se v odstavci ERROR (nebo CHYBY máte-li českou lokalizaci) dočteme o chybách, které mohou vzniknout. V případě, že send selže, bude hodnotou odpovídajícího makra zaplněná proměnná errno. Například pokud první parametrem funkce send nebude identifikátor soketu, ale nějaké číslo (nebude vrácené funkcí socket), funkce send vrátí -1 a proměnná errno bude nabývat hodnoty makra EBADF. Pro lepší a pohodlnější práci s proměnnou errno slouží některé funkce a další globální proměnné.
- void perror(const char *s); - vypíše na standardní chybový výstup textovou reprezentaci chyby.Parametrem je řetězec, který se vypíše společně s chybovou hláškou. Výstup bude mít tvar s:error, kde s je řetězec předán parametrem a error je textová reprezentace chyby, jejíž kód je uložen v proměnné errno. Funkce je vhodná pro konzolové aplikace případně pro jednoduché příklady, které já uvádím v seriálu. Pro GUI aplikace je myslím si naprosto nepoužitelná.
- char * strerror(int errnum); - vrátí textovou reprezentaci chyby, jejíž číslo je předáno parametrem. Funkce je deklarována v hlavičkovém souboru string.h. Voláním funkce strerror získáme ukazatel na chybovou hlášku. Problém je v tom, že řetězec na který se odkazujeme vráceným ukazatelem může být nezávisle na nás změněn jiným voláním perror nebo strerror. To by nám mohlo u vícevláknových aplikací vadit. Proto je zde k dispozici druhá varianta funkce strerror. Jmenuje se strerror_r.
- int strerror_r(int errnum, char *buf, size_t len); - funkce pro získání textové reprezentace chyby. Funkci lze bez obav použít ve vícevláknových aplikacích. Prvním parametrem je číselný kód chyby. Druhým parametrem je ukazatel na buffer. Buffer musí být alokován (minimálně na velikost posledního parametru). V bufferu nemusí být žádná smysluplná data. Buffer bude přepsán textem chybové hlášky. Posledním parametrem je maximální počet bytů, které funkce může vepsat do bufferu. Typicky velikost bufferu. Funkce vrací -1 v případě chyby nebo 0 v případě, že vše proběhlo v pořádku.
- const char * sys_errlist[]; - globální proměnná. Jedná se o pole řetězců chybových hlášek. V poli je pod každým indexem uložen řetězec s chybovou hláškou. Kód chybové hlášky je její index. Pole je definováno v hlavičkovém souboru errno.h.
- sys_nerr; - globální proměnná. Je definována v hlavičkovém souboru errno.h. Její hodnota udává počet prvků v poli sys_errlist. Neměli by jsme pole indexovat větší hodnotou než sys_nerr.
Parametrem funkce strerror a prvním parametrem strerror_r je většinou hodnota proměnné errno. Doporučuji používat raději tyto funkce než přímo indexovat pole sys_errlist. Indexem pole sys_errlist je také většinou hodnota proměnné errno. Při přímém přístupu k prvkům pole sys_error může nastat situace, že errno > sys_nerr - 1. Je to způsobeno tím, že některé nové chyby nemusí mít svou textovou reprezentaci. Zvláště u starších jader operačního systému. Budete-li přímo přistupovat k poli sys_errlist, nesmíte nikdy na tuto věc zapomenout.
Nyní si pro ukázku předvedeme, jak by vypadalo ošetření chyb při volání funkce connect.
Ošetření chyb funkce connect
|
Můžete zkusit zaplnit strukturu serverSock sice platnou IP adresou, ale špatným číslem portu. Mám na mysli číslo portu, na kterém na dané adrese určitě žádná aplikace neposlouchá. Zjistíte, že vznikne chyba, kterou nemám v konstrukci switch ošetřenou. Já jsem vycházel z manuálových stránek funkce connect, kde jsou jen některé chyby. Je u nich napsáno upozornění, že se nejedná o všechny chyby. Více chyb můžete například nalézt v manuálových stránkcách k pojmu TCP nebo IP.
Externí proměnná h_errnoPomocí errno můžeme rozpoznávat chyby vzniklé při volání celé škály funkcí, nejen funkcí majících nějakou souvislost se sokety. Aby to ale nebylo tak jednoduché, existuje ještě proměnná h_errno. Je používána nám již známou funkcí gethostbyaddr, která slouží pro překlad doménových jmen na IP adresy. Proměnná h_errno je používána více funkcemi, které mají nějakou souvislost s DNS.
Práce s proměnnou h_errno je velmi podobná práci s proměnnou errno. Zavoláme funkci gethostbyname a v případě že volání končí chybou (funkce vrací NULL), je kód chyby uložen v proměnné h_errno. Pro práci s proměnnou h_errno můžeme použít funkci herror.
- void herror(const char *s); - funkce má v podstatě stejný význam jako funkce perror. Rozdíl je jen v tom, že herror na rozdíl od perror pracuje s h_errno, nikoliv s errno. Funkce je deklarována v hlavičkovém souboru netdb.h.
Možná vám teď připadá, že proměnná h_errno je zbytečná. Že je to něco navíc. Že by jsme mohli používat errno ve všech případech. Alespoň mě to tak připadá. Zavedení dvou proměnných podle mne jen dělá zdrojový text nepřehledným. Jestli někdo zná důvod zavedení proměnné h_errno pro některé funkce, ať jej prosím napíše jako komentář pod článek.
S důvodem zavedení proměnné h_errno můžeme polemizovat a můžeme s ním dokonce i nesouhlasit. Ale to je tak asi všechno, co s tím můžeme udělat. Proto nám nezbývá nic jiného, než se podívat na ošetření chyb při volání funkce gethostbyname.
Ošetření chyb funkce gethostbyname
|
Tím jsme si ukázali, jak identifikovat a ošetřit chyby soketových funkcí. Dnes není nic ke stažení. Bylo by zbytečné vytvářet nějaké příklady. Zdrojové texty z článku si můžete sami vepsat do mých příkladů z předchozích článků. V programech by měly být ošetřeny všechny možné chyby. Já to ale ve svých budoucích článcích dělat nebudu. Mé příklady jsou jednoduché ukázky a nechci je mít příliš složité a nepřehledné.
Příště se podíváme na ošetření chyb soketových funkcí v MS Windows®.
Obsah seriálu (více o seriálu):
- Sokety a C++
- Překlad doménových jmen v Linuxu
- Překlad doménových jmen v MS Windows
- TCP klient v Linuxu
- TCP klient v MS Windows
- TCP server v Linuxu
- TCP server v MS Windows
- Protokol UDP 1.část
- Protokol UDP 2.část
- Zpracování chyb soketů v Linuxu
- Zpracování chyb soketů v MS Windows
Poslat článek
Nyní máte možnost poslat odkaz článku svým přátelům:
-
25. listopadu 2012
-
30. srpna 2002
-
10. října 2002
-
4. listopadu 2002
-
12. září 2002
-
25. listopadu 2012
-
28. července 1998
-
31. července 1998
-
28. srpna 1998
-
6. prosince 2000
-
27. prosince 2007
-
4. května 2007