Práce s volbami soketů v Linuxu
- int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); – funkce zjistí hodnotu nějaké volby soketu. Prvním parametrem je identifikátor soketu, druhým parametrem je úroveň volby. Třetím parametrem je název volby. Tyto dva parametry přesně určují atribut, jehož hodnotu se snažíme přečíst. Čtvrtým parametrem je ukazatel na blok paměti, ve kterém se po zavolání funkce bude nacházet požadovaný výsledek. Posledním parametrem je ukazatel na číslo udávající velikost alokované paměti, na kterou se odkazuje předposlední parametr. Před zavoláním funkce musí ukazovat ukazatel optval na souvislý blok alokované paměti. Velikost paměti musí být uložena v čísle, na které se odkazuje poslední ukazatel. Po zavolání funkce může blok paměti daný předposledním parametrem změnit velikost. Nová velikost alokované paměti je uložena v čísle, na které se odkazuje poslední parametr. Funkce vrací 0 v případě úspěchu. V opačném případě vrací –1.
- int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); – funkce nastaví hodnotu nějaké volby soketu. Prvním parametrem je identifikátor soketu, druhým parametrem je úroveň volby. Třetím parametrem je název volby. Tyto dva parametry přesně určují atribut, jehož hodnotu se snažíme nastavit. Čtvrtým parametrem je ukazatel na blok paměti, ve kterém se nachází zadávaná hodnota. Posledním parametrem je velikost alokované paměti, na kterou se odkazuje předposlední parametr. Funkce vrací 0 v případě úspěchu. V opačném případě vrací –1.
Práce s volbami soketů v MS WindowsŽ
Význam parametrů funkcí ve WinSock je v podstatě stejný jako v „klasickém“ soketovém API. Jen typy parametrů se trochu liší.
- int getsockopt(SOCKET s, int level, int optname, char* optval, int* optlen); – funkce zjistí hodnotu nějaké volby soketu. Prvním parametrem je identifikátor soketu, druhým parametrem je úroveň volby. Třetím parametrem je název volby. Tyto dva parametry přesně určují atribut, jehož hodnotu se snažíme přečíst. Čtvrtým parametrem je ukazatel na blok paměti, ve kterém se po zavolání funkce bude nacházet požadovaný výsledek. Posledním parametrem je ukazatel na číslo udávající velikost alokované paměti, na kterou se odkazuje předposlední parametr. Před zavoláním funkce musí ukazovat ukazatel optval na souvislý blok alokované paměti. Velikost paměti musí být uložena v čísle, na které se odkazuje poslední ukazatel. Po zavolání funkce může blok paměti určený předposledním parametrem změnit velikost. Nová velikost alokované paměti je uložena v čísle, na které se odkazuje poslední parametr. Funkce vrací 0 v případě úspěchu. V opačném případě vrací SOCKET_ERROR.
- int setsockoptSOCKET s, int level, int optname, const char* optval, int optlen); – funkce nastaví hodnotu nějaké volby soketu. Prvním parametrem je identifikátor soketu, druhým parametrem je úroveň volby. Třetím parametrem je název volby. Tyto dva parametry přesně určují atribut, jehož hodnotu se snažíme nastavit. Čtvrtým parametrem je ukazatel na blok paměti, ve kterém se nachází zadávaná hodnota. Posledním parametrem je velikost alokované paměti, na kterou se odkazuje předposlední parametr. Funkce vrací 0 v případě úspěchu. V opačném případě vrací hodnotu makra SOCKET_ERROR.
Úrovně voleb
Parametry soketu lze měnit na různých vrstvách síťového modelu. Druhým parametrem funkcí setsockopt a getsockopt určujeme, na které vrstvě se nachází vlastnost, s níž chceme pracovat. Nejčastěji budeme asi používat následující úrovně (za parametr level budeme dosazovat):
- SOL_SOCKET – obecné vlastnosti soketu
- SOL_TCP (ve WinSock IPPROTO_TCP) – vlastnosti související s protokolem TCP
- SOL_IP (ve WinSock IPPROTO_IP) – vlastnosti související s IP protokolem
Názvy úrovní (stejně jako názvy voleb) jsou makra. Chceme-li pracovat s úrovní SOL_TCP, musíme vložit (include) hlavičkový soubornetinet/tcp.h.
Příklady
Existuje mnoho voleb pro různé protokoly. My si tady jako příklad uvedeme pět voleb.
Urgentní a „normální“ data v jedné frontě
Existuje možnost, jak zajistit, aby příchozí urgentní data byla vkládána společně s daty „normálními“ do jedné fronty. S volbou se pracuje v úrovni SOL_SOCKET. Název volby je SO_OOBINLINE. Hodnota volby je typu
int. Je-li hodnota nenulová, jsou urgentní data vkládána společně s neurentnímy daty do jedné fronty. Lze je přečíst bez příznaku MSG_OOB. Je-li hodnota 0, jsou příchozí urgentní data vkládána do jiné fronty než data neurgentní. K jejich přečtení je potřeba použít příznak MSG_OOB. Protože datový typ bool reprezentuje hodnotu false jako 0 a hodnotu true jako 1, lze pracovat s typem bool místo int.
/* soc je vytvořený soket. */
bool oob;
socklen_t l = sizeof(int);
/* Zjistím, zda jsou urgentní společně s neurg. v jedné frontě. */
if (getsockopt(soc, SOL_SOCKET, SO_OOBINLINE, &oob, &l) != 0)
{
// Problém
}
if (oob)
{
cout << "Jsou v jedné frontě" << endl;
}
else
{
cout << "Jsou odděleně" << endl;
}
/* Nastavím opačnou hodnotu. */
oob = !oob;
if (setsockopt(soc, SOL_SOCKET, SO_OOBINLINE, &oob, sizeof(int)) != 0)
{
// Problém
}
Nastavení bufferu
Jako další příklad práce s vlastnostmi na úrovni SOL_SOCKET si uvedeme přečtení a nastavení velikosti přijímacího a odesílacího bufferu. Volba určující velikost přijímacího bufferu má název SO_RCVBUF. Volba určující velikost odesílacího bufferu má název SO_SNDBUF.
/* soc je vytvořený soket. */
int bufferSize = 0;
socklen_t l = sizeof(bufferSize);
/* Zjistím velikost bufferu pro odchozí data */
if (getsockopt(soc, SOL_SOCKET, SO_SNDBUF, &bufferSize, &l) != 0)
{
// Problém
}
cout << "Velikost odchozího bufferu je " << bufferSize << endl;
bufferSize = 10000;
/* Nastavím velikost bufferu pro odchozí data. */
setsockopt(soc, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
/* Nastavím velikost bufferu pro příchozí data. */
setsockopt(soc, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
Maximální velikost TCP segmentu
Jako příklad práce s vlastností na úrovni SOL_TCP si ukážeme přečtení maximální velikosti odchozích TCP segmentů.
/* soc je vytvořený soket. */
int sizeSeg = 0;
socklen_t l = sizeof(size);
if (getsockopt(soc, SOL_TCP, TCP_MAXSEG, &sizeSeg, &l) != 0)
{
// Problém
}
cout << "Maximální velikost odchozího tcp segmentu je " << sizeSeg << endl;
Položka TTL v hlaviččce IP paketu – doba životnosti paketu
V hlaviččce IP datagramu existuje položka nazývaná TTL (Time To Live). Jedná se o celé číslo, které udává, kolika směrovači ještě může paket projít. Každý směrovač sníží hodnotu TTL o 1. V případě, že nová hodnota je 0, dojde k zahození paketu. Položka TTL slouží k tomu, aby v síti do nekonečna nekolovaly „zbloudilé“ pakety. Zjištění hodnoty TTL u všech IP paketů odesílaných pomocí daného soketu lze provést pomocí volby IP_TTL. Úroveň vlastnosti je SOL_IP.
/* soc je vytvořený soket. */
int ttl = 0; lenght = sizeof(ttl);
if (getsockopt(soc, SOL_IP, IP_TTL, &ttl, &lenght) != 0)
{
// Problém
}
cout << "Doba životnosti odchozího IP paketu je " << ttl << endl;
Je zřejmé, že ne všechny volby lze použít na všechny typy soketů. Vždy je nutné dostatečně prostudovat dokumentaci k jednotlivým komunikačním protokolům. Příště se podíváme na takzvané „RAW“ sokety.