Vítejte v nádherném světě přenositelnosti... nebo spíše jejího nedostatku. Než začneme tyto dvě možnosti podrobně analyzovat a podíváme se hlouběji na to, jak s nimi nakládají různé operační systémy, je třeba poznamenat, že implementace BSD socketu je matkou všech implementací socketů. V podstatě všechny ostatní systémy v určitém okamžiku zkopírovaly implementaci soketu BSD (nebo alespoň jeho rozhraní) a poté jej začaly vyvíjet samy. Implementace BSD socketu se samozřejmě vyvíjela také ve stejnou dobu, a tak systémy, které ji zkopírovaly později, získaly funkce, které v systémech, které ji zkopírovaly dříve, chyběly. Pochopení implementace soketu BSD je klíčem k pochopení všech ostatních implementací soketu, takže byste si o tom měli přečíst, i když vás nezajímá psát kód pro systém BSD.
Než se podíváme na tyto dvě možnosti, měli byste vědět několik základních věcí. Připojení TCP/UDP je identifikováno n-ticí pěti hodnot:
{<protocol>, <src addr>, <src port>, <dest addr>, <dest port>}
Jakákoli jedinečná kombinace těchto hodnot identifikuje spojení. Výsledkem je, že žádná dvě spojení nemohou mít stejných pět hodnot, jinak by systém již nebyl schopen tato spojení rozlišit.
Protokol soketu je nastaven, když je soket vytvořen pomocí socket()
funkce. Zdrojová adresa a port se nastavují pomocí bind()
funkce. Cílová adresa a port se nastavují pomocí connect()
funkce. Protože UDP je protokol bez připojení, lze zásuvky UDP používat i bez jejich připojení. Přesto je možné je propojit a v některých případech velmi výhodné pro váš kód a obecný návrh aplikace. V režimu bez připojení jsou sokety UDP, které nebyly explicitně svázány, když jsou přes ně poprvé odeslána data, obvykle automaticky svázány systémem, protože nesvázaný soket UDP nemůže přijímat žádná (odpovědní) data. Totéž platí pro nevázaný TCP soket, je automaticky svázán předtím, než bude připojen.
Pokud explicitně svážete soket, je možné jej svázat s portem 0
, což znamená „jakýkoli port“. Vzhledem k tomu, že socket nemůže být skutečně vázán na všechny existující porty, bude si systém muset v takovém případě vybrat konkrétní port sám (obvykle z předdefinovaného, OS specifického rozsahu zdrojových portů). Podobný zástupný znak existuje pro zdrojovou adresu, kterou může být „libovolná adresa“ (0.0.0.0
v případě IPv4 a ::
v případě IPv6). Na rozdíl od portů může být socket skutečně vázán na "libovolnou adresu", což znamená "všechny zdrojové IP adresy všech lokálních rozhraní". Pokud je zásuvka připojena později, systém musí zvolit konkrétní zdrojovou IP adresu, protože zásuvku nelze připojit a zároveň být vázána na jakoukoli lokální IP adresu. V závislosti na cílové adrese a obsahu směrovací tabulky systém vybere vhodnou zdrojovou adresu a nahradí „libovolnou“ vazbu vazbou na vybranou zdrojovou IP adresu.
Ve výchozím nastavení nemohou být žádné dva sokety vázány na stejnou kombinaci zdrojové adresy a zdrojového portu. Dokud je zdrojový port jiný, je zdrojová adresa ve skutečnosti irelevantní. Vazba socketA
na ipA:portA
a socketB
na ipB:portB
je vždy možné, pokud ipA != ipB
platí, i když portA == portB
. Např. socketA
patří k programu serveru FTP a je vázán na 192.168.0.1:21
a socketB
patří k jinému programu FTP serveru a je vázán na 10.0.0.1:21
, obě vazby budou úspěšné. Mějte však na paměti, že soket může být lokálně vázán na „libovolnou adresu“. Pokud je soket vázán na 0.0.0.0:21
, je svázán se všemi existujícími lokálními adresami současně a v takovém případě nemůže být žádný další soket svázán s portem 21
, bez ohledu na to, ke které konkrétní IP adrese se pokusí navázat, jako 0.0.0.0
koliduje se všemi existujícími místními IP adresami.
Vše, co bylo dosud řečeno, je téměř stejné pro všechny hlavní operační systémy. Věci začnou být specifické pro OS, když do hry vstoupí opětovné použití adresy. Začínáme s BSD, protože jak jsem řekl výše, je to matka všech implementací socketů.
BSD
SO_REUSEADDR
Pokud SO_REUSEADDR
je povolena na soketu před jeho vázáním, lze soket úspěšně svázat, pokud nedojde ke konfliktu s jiným soketem vázaným přesně stejnou kombinaci zdrojové adresy a portu. Možná se teď ptáte, jak je to jiné než dříve? Klíčové slovo je „přesně“. SO_REUSEADDR
hlavně mění způsob, jakým se při hledání konfliktů zachází s adresami se zástupnými znaky („jakákoli IP adresa“).
Bez SO_REUSEADDR
, vazba socketA
na 0.0.0.0:21
a poté svázáním socketB
na 192.168.0.1:21
selže (s chybou EADDRINUSE
), protože 0.0.0.0 znamená "libovolná místní IP adresa", takže všechny místní IP adresy jsou považovány za používané tímto soketem, a to včetně 192.168.0.1
, také. S SO_REUSEADDR
bude to úspěšné, protože 0.0.0.0
a 192.168.0.1
nejsou přesně stejná adresa, jedna je zástupný znak pro všechny místní adresy a druhá je velmi specifická místní adresa. Všimněte si, že výše uvedené tvrzení platí bez ohledu na to, v jakém pořadí socketA
a socketB
jsou svázáni; bez SO_REUSEADDR
vždy selže, s SO_REUSEADDR
vždy se to podaří.
Pro lepší přehled si zde udělejme tabulku a uveďme všechny možné kombinace:
SO_REUSEADDR socketA socketB Result --------------------------------------------------------------------- ON/OFF 192.168.0.1:21 192.168.0.1:21 Error (EADDRINUSE) ON/OFF 192.168.0.1:21 10.0.0.1:21 OK ON/OFF 10.0.0.1:21 192.168.0.1:21 OK OFF 0.0.0.0:21 192.168.1.0:21 Error (EADDRINUSE) OFF 192.168.1.0:21 0.0.0.0:21 Error (EADDRINUSE) ON 0.0.0.0:21 192.168.1.0:21 OK ON 192.168.1.0:21 0.0.0.0:21 OK ON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE)
Výše uvedená tabulka předpokládá, že socketA
již bylo úspěšně svázáno s adresou zadanou pro socketA
a poté socketB
je vytvořen, buď získá SO_REUSEADDR
set nebo ne, a nakonec je vázán na adresu uvedenou pro socketB
. Result
je výsledkem operace vazby pro socketB
. Pokud první sloupec říká ON/OFF
, hodnota SO_REUSEADDR
je pro výsledek irelevantní.
Dobře, SO_REUSEADDR
má vliv na adresy se zástupnými znaky, dobré vědět. To však není jediný účinek, který má. Existuje další dobře známý efekt, který je také důvodem, proč většina lidí používá SO_REUSEADDR
v serverových programech na prvním místě. Pro další důležité použití této možnosti se musíme hlouběji podívat na to, jak protokol TCP funguje.
Pokud je soket TCP zavírán, obvykle se provádí 3-cestný handshake; sekvence se nazývá FIN-ACK
. Problém je v tom, že poslední ACK této sekvence může na druhé straně dorazit nebo nedorazil a pouze pokud ano, druhá strana také považuje socket za plně uzavřený. Aby se zabránilo opětovnému použití kombinace adresa+port, kterou mohou někteří vzdálení peer stále považovat za otevřenou, nebude systém po odeslání posledního ACK
okamžitě považovat soket za mrtvý. ale místo toho uveďte soket do stavu běžně označovaného jako TIME_WAIT
. V tomto stavu může být několik minut (nastavení v závislosti na systému). Na většině systémů můžete tento stav obejít povolením prodlevy a nastavením doby prodlevy na nulu1, ale neexistuje žádná záruka, že je to vždy možné, že systém vždy vyhoví tomuto požadavku, a i když jej systém vyhoví, způsobí to zásuvka, která má být uzavřena resetem (RST
), což není vždy skvělý nápad. Chcete-li se dozvědět více o prodlení, podívejte se na mou odpověď na toto téma.
Otázkou je, jak systém zachází se socketem ve stavu TIME_WAIT
? Pokud SO_REUSEADDR
není nastaven, soket ve stavu TIME_WAIT
je považováno za stále vázáno na zdrojovou adresu a port a jakýkoli pokus o navázání nového soketu na stejnou adresu a port selže, dokud nebude soket skutečně uzavřen. Neočekávejte tedy, že zdrojovou adresu soketu můžete znovu svázat ihned po jeho zavření. Ve většině případů to selže. Pokud však SO_REUSEADDR
je nastaven pro soket, který se pokoušíte svázat, jiný soket svázaný se stejnou adresou a portem ve stavu TIME_WAIT
je jednoduše ignorován, koneckonců je již „napůl mrtvý“ a váš socket se může bez problému vázat na přesně stejnou adresu. V tom případě nehraje žádnou roli, že druhý socket může mít přesně stejnou adresu a port. Všimněte si, že navázání soketu na přesně stejnou adresu a port jako umírající soket v TIME_WAIT
stav může mít neočekávané a obvykle nežádoucí vedlejší účinky v případě, že druhá zásuvka je stále "v provozu", ale to je nad rámec této odpovědi a naštěstí jsou tyto vedlejší účinky v praxi spíše vzácné.
Je tu jedna poslední věc, kterou byste měli vědět o SO_REUSEADDR
. Vše napsané výše bude fungovat, pokud má soket, ke kterému se chcete připojit, povoleno opakované použití adresy. Není nutné, aby druhý soket, ten, který je již svázán nebo je v TIME_WAIT
stát, také měl tento příznak nastaven, když byl vázán. Kód, který rozhoduje, zda bude vazba úspěšná nebo selže, pouze kontroluje SO_REUSEADDR
příznak zásuvky vložený do bind()
volání, u všech ostatních kontrolovaných soketů se na tento příznak ani nehledí.
SO_REUSEPORT
SO_REUSEPORT
je to, co by většina lidí očekávala SO_REUSEADDR
být. V podstatě SO_REUSEPORT
umožňuje svázat libovolný počet soketů na přesně stejnou zdrojovou adresu a port, pokud všechny předchozí vázané sokety měly také SO_REUSEPORT
nastaveny před tím, než byly svázány. Pokud první soket, který je vázán na adresu a port, nemá SO_REUSEPORT
nastaven, žádný jiný soket nemůže být svázán s přesně stejnou adresou a portem, bez ohledu na to, zda má tento druhý soket SO_REUSEPORT
nastavit nebo ne, dokud první zásuvka opět neuvolní svou vazbu. Na rozdíl od případu SO_REUESADDR
kód zpracovávající SO_REUSEPORT
nejen ověří, že aktuálně vázaný soket má SO_REUSEPORT
set, ale také ověří, že soket s konfliktní adresou a portem měl SO_REUSEPORT
nastaveno, když bylo svázáno.
SO_REUSEPORT
neznamená SO_REUSEADDR
. To znamená, pokud zásuvka neměla SO_REUSEPORT
nastaven, když byl svázán a jiný soket má SO_REUSEPORT
nastaven, když je vázán na přesně stejnou adresu a port, vazba selže, což se očekává, ale také se nezdaří, pokud druhý soket již umírá a je v TIME_WAIT
Stát. Aby bylo možné svázat soket se stejnými adresami a portem jako jiný soket v TIME_WAIT
stav vyžaduje buď SO_REUSEADDR
nastavit na této zásuvce nebo SO_REUSEPORT
musí být nastaveno na obou zásuvky před jejich spojením. Samozřejmě je možné nastavit obojí, SO_REUSEPORT
a SO_REUSEADDR
, na zásuvce.
O SO_REUSEPORT
toho není moc co říci kromě toho byl přidán později než SO_REUSEADDR
, to je důvod, proč jej nenajdete v mnoha implementacích soketů jiných systémů, které "forkovaly" kód BSD před přidáním této možnosti, a že před tímto neexistoval způsob, jak spojit dva sokety s přesně stejnou adresou soketu v BSD možnost.
Connect() vrací EADDRINUSE?
Většina lidí ví, že bind()
může selhat s chybou EADDRINUSE
když si však začnete hrát s opětovným použitím adresy, můžete se dostat do podivné situace, že connect()
selže i s touto chybou. Jak to může být? Jak může být vzdálená adresa, po tom všem, co connect přidává do soketu, již používána? Připojení více zásuvek k přesně stejné vzdálené adrese nikdy předtím nebyl problém, takže co je tady špatně?
Jak jsem řekl úplně nahoře ve své odpovědi, spojení je definováno n-ticí pěti hodnot, vzpomínáte? A také jsem řekl, že těchto pět hodnot musí být jedinečných, jinak systém už nedokáže rozlišit dvě spojení, že? Díky opětovnému použití adresy můžete svázat dva sokety stejného protokolu se stejnou zdrojovou adresou a portem. To znamená, že tři z těchto pěti hodnot jsou již pro tyto dva sokety stejné. Pokud se nyní pokusíte připojit oba tyto sokety také na stejnou cílovou adresu a port, vytvoříte dva spojené sokety, jejichž n-tice jsou naprosto identické. To nemůže fungovat, alespoň ne pro TCP spojení (UDP spojení stejně nejsou žádná skutečná spojení). Pokud data dorazila pro jedno ze dvou připojení, systém nedokázal určit, ke kterému připojení data patří. Alespoň cílová adresa nebo cílový port musí být pro každé připojení odlišné, aby systém neměl problém identifikovat, ke kterému připojení příchozí data patří.
Pokud tedy svážete dva sokety stejného protokolu se stejnou zdrojovou adresou a portem a pokusíte se je oba připojit ke stejné cílové adrese a portu, connect()
ve skutečnosti selže s chybou EADDRINUSE
pro druhou zásuvku, kterou se pokoušíte připojit, což znamená, že zásuvka s identickou n-ticí pěti hodnot je již připojena.
Adresy vícesměrového vysílání
Většina lidí ignoruje skutečnost, že multicastové adresy existují, ale existují. Zatímco unicastové adresy se používají pro komunikaci jeden ku jedné, multicastové adresy se používají pro komunikaci 1 ku mnoha. Většina lidí se dozvěděla o multicastových adresách, když se dozvěděli o IPv6, ale multicastové adresy existovaly také v IPv4, i když tato funkce nebyla na veřejném internetu nikdy široce používána.
Význam SO_REUSEADDR
změny pro adresy vícesměrového vysílání, protože umožňuje, aby bylo více soketů svázáno s přesně stejnou kombinací zdrojové adresy vícesměrového vysílání a portu. Jinými slovy, pro vícesměrové adresy SO_REUSEADDR
chová se přesně jako SO_REUSEPORT
pro unicast adresy. Ve skutečnosti kód zpracovává SO_REUSEADDR
a SO_REUSEPORT
identicky pro vícesměrové adresy, to znamená, že byste mohli říci, že SO_REUSEADDR
znamená SO_REUSEPORT
pro všechny multicastové adresy a naopak.
FreeBSD/OpenBSD/NetBSD
To vše jsou poněkud pozdní forky původního kódu BSD, proto všechny tři nabízejí stejné možnosti jako BSD a také se chovají stejně jako v BSD.
macOS (MacOS X)
Ve svém jádru je macOS jednoduše UNIX ve stylu BSD s názvem „Darwin “, založený na poměrně pozdním rozvětvení kódu BSD (BSD 4.3), který byl později dokonce znovu synchronizován s (v té době aktuální) kódovou základnou FreeBSD 5 pro vydání Mac OS 10.3, takže Apple mohl získat plná kompatibilita s POSIX (macOS má certifikaci POSIX). Navzdory tomu, že jeho jádrem je mikrojádro ("Mach "), zbytek jádra ("XNU ") je v podstatě jen jádro BSD, a proto macOS nabízí stejné možnosti jako BSD a také se chovají stejně jako v BSD.
iOS / watchOS / tvOS
iOS je jen macOS fork s mírně upraveným a ořezaným jádrem, poněkud okleštěnou sadou nástrojů pro uživatelský prostor a mírně odlišnou výchozí sadou rámců. watchOS a tvOS jsou iOS forky, které jsou ještě dále zkráceny (zejména watchOS). Podle mého nejlepšího vědomí se všechny chovají přesně jako macOS.
Linux
Linux <3.9
Před Linuxem 3.9 pouze možnost SO_REUSEADDR
existoval. Tato volba se chová obecně stejně jako v BSD se dvěma důležitými výjimkami:
-
Dokud je naslouchající (serverový) soket TCP vázán na konkrétní port,
SO_REUSEADDR
možnost je zcela ignorována pro všechny sokety zaměřené na tento port. Navázání druhého soketu na stejný port je možné pouze tehdy, pokud to bylo možné také v BSD bezSO_REUSEADDR
soubor. Např. nemůžete se vázat na zástupnou adresu a poté na konkrétnější nebo naopak, obojí je možné v BSD, pokud nastavíteSO_REUSEADDR
. Co můžete udělat, je, že se můžete vázat na stejný port a dvě různé adresy bez zástupných znaků, protože to je vždy povoleno. V tomto ohledu je Linux restriktivnější než BSD. -
Druhou výjimkou je, že pro klientské sokety se tato volba chová přesně jako
SO_REUSEPORT
v BSD, pokud oba měli tento příznak nastaven před tím, než byli svázáni. Důvodem pro to bylo jednoduše to, že je důležité mít možnost svázat více soketů na přesně stejnou adresu soketu UDP pro různé protokoly a protože dříve neexistoval žádnýSO_REUSEPORT
před verzí 3.9 chováníSO_REUSEADDR
byl odpovídajícím způsobem změněn, aby tuto mezeru zaplnil. V tomto ohledu je Linux méně omezující než BSD.
Linux>=3.9
Linux 3.9 přidal možnost SO_REUSEPORT
i na Linux. Tato volba se chová přesně jako volba v BSD a umožňuje vazbu na přesně stejnou adresu a číslo portu, pokud mají všechny sokety tuto volbu nastavenou před jejich navázáním.
Stále však existují dva rozdíly oproti SO_REUSEPORT
na jiných systémech:
-
Aby se zabránilo „ukradení portu“, existuje jedno speciální omezení:Všechny sokety, které chtějí sdílet stejnou adresu a kombinaci portů, musí patřit k procesům, které sdílejí stejné efektivní ID uživatele! Takže jeden uživatel nemůže "ukrást" porty jiného uživatele. Toto je nějaké speciální kouzlo, které trochu kompenzuje chybějící
SO_EXCLBIND
/SO_EXCLUSIVEADDRUSE
příznaky. -
Kromě toho jádro provádí nějaké "zvláštní kouzlo" pro
SO_REUSEPORT
sokety, které se nenacházejí v jiných operačních systémech:U soketů UDP se snaží distribuovat datagramy rovnoměrně, u naslouchacích soketů TCP se pokouší distribuovat příchozí požadavky na připojení (ty, které jsou přijímány volánímaccept()
) rovnoměrně napříč všemi sokety, které sdílejí stejnou kombinaci adres a portů. Aplikace tak může snadno otevřít stejný port ve více podřízených procesech a poté použítSO_REUSEPORT
získat velmi levné vyrovnávání zátěže.
Android
I když se celý systém Android poněkud liší od většiny linuxových distribucí, v jádru funguje mírně upravené linuxové jádro, takže vše, co platí pro Linux, by mělo platit i pro Android.
Windows
Windows zná pouze SO_REUSEADDR
možnost, není zde SO_REUSEPORT
. Nastavení SO_REUSEADDR
na socketu ve Windows se chová jako nastavení SO_REUSEPORT
a SO_REUSEADDR
na soketu v BSD, s jednou výjimkou:
Před Windows 2003, socket s SO_REUSEADDR
mohl být vždy vázán na přesně stejnou zdrojovou adresu a port jako již vázaný soket, i když druhý soket neměl tuto možnost nastavenou, když byl vázán . Toto chování umožnilo aplikaci „ukrást“ připojený port jiné aplikace. Netřeba dodávat, že to má zásadní bezpečnostní důsledky!
Microsoft si to uvědomil a přidal další důležitou možnost soketu:SO_EXCLUSIVEADDRUSE
. Nastavení SO_EXCLUSIVEADDRUSE
na soketu zajišťuje, že pokud je vazba úspěšná, je kombinace zdrojové adresy a portu vlastněna výhradně tímto soketem a žádný jiný soket se na ně nemůže vázat, ani pokud má SO_REUSEADDR
set.
Toto výchozí chování bylo změněno nejprve ve Windows 2003, Microsoft tomu říká "Enhanced Socket Security" (vtipný název pro chování, které je výchozí ve všech ostatních hlavních operačních systémech). Pro více podrobností stačí navštívit tuto stránku. Existují tři tabulky:První ukazuje klasické chování (stále se používá při použití režimů kompatibility!), druhá ukazuje chování Windows 2003 a vyšší, když bind()
volání provádí stejný uživatel a třetí, když je bind()
hovory uskutečňují různí uživatelé.
Solaris
Solaris je nástupcem SunOS. SunOS byl původně založen na vidlici BSD, SunOS 5 a později byl založen na vidlici SVR4, nicméně SVR4 je sloučením BSD, System V a Xenix, takže do určité míry je Solaris také vidlice BSD a spíše raný. Výsledkem je, že Solaris zná pouze SO_REUSEADDR
, neexistuje žádný SO_REUSEPORT
. SO_REUSEADDR
chová se v podstatě stejně jako v BSD. Pokud vím, neexistuje způsob, jak dosáhnout stejného chování jako SO_REUSEPORT
v Solaris, to znamená, že není možné svázat dva sokety s přesně stejnou adresou a portem.
Podobně jako Windows má Solaris možnost dát zásuvce exkluzivní vazbu. Tato volba se jmenuje SO_EXCLBIND
. Pokud je tato možnost nastavena na soketu před jeho navázáním, nastavení SO_REUSEADDR
na jiném soketu nemá žádný účinek, pokud jsou dva sokety testovány na konflikt adres. Např. pokud socketA
je vázán na zástupnou adresu a socketB
má SO_REUSEADDR
povoleno a je vázáno na jinou než zástupnou adresu a stejný port jako socketA
, bude tato vazba normálně úspěšná, pokud není socketA
měl SO_EXCLBIND
povoleno, v takovém případě selže bez ohledu na SO_REUSEADDR
vlajka socketB
.
Jiné systémy
V případě, že váš systém není uveden výše, napsal jsem malý testovací program, pomocí kterého můžete zjistit, jak váš systém zvládá tyto dvě možnosti. Také pokud si myslíte, že mé výsledky jsou nesprávné , prosím nejprve spusťte tento program, než zveřejníte jakékoli komentáře a případně uvedete nepravdivá tvrzení.
Vše, co kód vyžaduje ke sestavení, je trochu POSIX API (pro síťové části) a kompilátor C99 (ve skutečnosti většina kompilátorů jiných než C99 bude fungovat dobře, pokud nabízí inttypes.h
a stdbool.h
; např. gcc
podporoval oba dlouho předtím, než nabídl plnou podporu C99).
Vše, co program potřebuje ke spuštění, je, že alespoň jedno rozhraní ve vašem systému (jiné než lokální rozhraní) má přidělenou IP adresu a že je nastavena výchozí trasa, která toto rozhraní používá. Program shromáždí tuto IP adresu a použije ji jako druhou "specifickou adresu".
Testuje všechny možné kombinace, na které si vzpomenete:
- Protokoly TCP a UDP
- Normální sokety, naslouchací (serverové) sokety, multicastové sokety
SO_REUSEADDR
nastavte na socket1, socket2 nebo oba socketySO_REUSEPORT
nastavte na socket1, socket2 nebo oba sockety- Všechny kombinace adres, které můžete vytvořit z
0.0.0.0
(zástupný znak),127.0.0.1
(konkrétní adresa) a druhá konkrétní adresa nalezená ve vašem primárním rozhraní (pro vícesměrové vysílání je to jen224.1.2.3
ve všech testech)
a vytiskne výsledky v pěkné tabulce. Bude také fungovat na systémech, které neznají SO_REUSEPORT
, v takovém případě tato možnost jednoduše není testována.
Co program nemůže snadno otestovat, je jak SO_REUSEADDR
funguje na soketech v TIME_WAIT
stavu, protože je velmi složité vynutit a udržet zásuvku v tomto stavu. Naštěstí se zdá, že většina operačních systémů se zde jednoduše chová jako BSD a většinu času mohou programátoři existenci tohoto stavu jednoduše ignorovat.
Zde je kód (nemohu ho sem zahrnout, odpovědi mají limit velikosti a kód by tuto odpověď posunul nad limit).
Meckiho odpověď je naprosto perfektní, ale stojí za to dodat, že FreeBSD také podporuje SO_REUSEPORT_LB
, který napodobuje Linux' SO_REUSEPORT
chování - vyrovnává zátěž; viz setsockopt(2)