Blokowanie gniazd: kiedy dokładnie powróci "send ()"?

Kiedy dokładnie Funkcja Gniazda BSD send() powróci do wywołującego?

W trybie nieblokującym , powinien natychmiast powrócić, prawda?

Jeśli chodzi o blokowanie trybu, strona podręcznika mówi:

Gdy wiadomość nie mieści się w buforze wysyłania gniazda, send() normalnie blokuje, chyba że gniazdo zostało umieszczone w trybie nieblokującym We/Wy.

Pytania:

  1. czy to znaczy że wywołanie send() zawsze powróci natychmiast, jeśli w buforze wysyłania jądra jest miejsce?
  2. czy zachowanie i wydajność wywołania send() jest identyczne dla TCP i UDP? Jeśli nie, to dlaczego?
Author: David Citron, 2011-03-23

5 answers

Czy to oznacza, że wywołanie send() zawsze powróci natychmiast, jeśli w buforze wysyłania jądra jest miejsce?

Tak. Tak długo, jak od razu oznacza to, że pamięć, którą podałeś, została skopiowana do bufora jądra. Co w niektórych przypadkach może nie być tak natychmiastowe. Na przykład, jeśli podany wskaźnik wywoła Błąd strony, który wymaga wciągnięcia bufora z pliku mapowanego w pamięci lub wymiany, spowoduje to znaczne opóźnienie wywołania wracam.

Czy zachowanie i wydajność wywołania send() są identyczne dla TCP i UDP? Jeśli nie, to dlaczego?

Niezupełnie. Możliwe różnice w wydajności zależą od implementacji stosu TCP/IP przez system operacyjny. Teoretycznie Gniazdo UDP może być nieco tańsze, ponieważ system operacyjny musi z nim robić mniej rzeczy.

EDIT: z drugiej strony, ponieważ możesz wysłać znacznie więcej danych na wywołanie systemowe za pomocą TCP, zazwyczaj koszt za bajt może być dużo niższy z TCP. Można to złagodzić za pomocą sendmmsg () W ostatnich jądrach Linuksa.

Jeśli chodzi o zachowanie, jest prawie identyczne.

Do blokowania gniazd, zarówno TCP, jak i UDP będą blokować, dopóki nie będzie miejsca w buforze jądra. Różnica polega jednak na tym, że gniazdo UDP będzie czekać, aż cały bufor będzie mógł być zapisany w buforze jądra, podczas gdy gniazdo TCP może zdecydować się skopiować tylko jeden bajt do bufora jądra (zazwyczaj jest to więcej niż jeden bajt chociaż).

Jeśli spróbujesz wysłać pakiety większe niż 64kiB, Gniazdo UDP będzie prawdopodobnie konsekwentnie zawierało EMSGSIZE. Dzieje się tak dlatego, że UDP, będąc gniazdem datagramu , gwarantuje wysłanie całego bufora jako pojedynczego pakietu IP (lub pociągu fragmentów pakietów IP) lub w ogóle go nie wysyła.

Gniazda nieblokujące zachowują się identycznie jak wersje blokujące z jednym wyjątkiem, który zamiast blokować (w przypadku, gdy nie ma wystarczającej ilości miejsca w jądrze bufor), wywołania nie powiodą się z EAGAIN (lub EWOULDBLOCK). Gdy tak się stanie, nadszedł czas, aby umieścić gniazdo z powrotem w epoll / kqueue / select (lub cokolwiek używasz), aby poczekać, aż stanie się ponownie zapisywalne.

Jak zwykle podczas pracy z POSIX, należy pamiętać, że wywołanie może się nie udać z EINTR (jeśli wywołanie zostało przerwane sygnałem). W tym przypadku najprawdopodobniej chcesz ponownie zadzwonić send().

 28
Author: Arvid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-06 15:10:00

Jeśli w buforze jądra jest miejsce, to send() skopiuje do bufora tyle bajtów ile się da i natychmiast zakończy działanie, zwracając ile bajtów zostało faktycznie skopiowanych (może być ich mniej niż wymagano). Jeśli w buforze jądra nie ma miejsca, to send() blokuje się, dopóki jedno z tych miejsc nie stanie się dostępne lub wystąpi timeout (jeśli jedno jest skonfigurowane).

 5
Author: Remy Lebeau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-25 02:11:38

Send () powróci, gdy tylko dane zostaną zaakceptowane przez jądro. W przypadku zablokowania gniazda: send() zablokuje się, jeśli bufor jądra nie jest wystarczająco wolny, aby pobierać dane dostarczone do wywołania send ().

Non blocking sockets: send() nie zablokuje, ale zawiedzie i zwróci -1 lub może zwrócić liczbę bajtów skopiowanych częściowo (w zależności od dostępnego miejsca w buforze). Ustawia errno EWOULDBLOCK lub EAGAIN. Oznacza to, że w czasie send () bufor nie był w stanie pobranie wszystkich bajtów i powinieneś spróbować ponownie za pomocą funkcji select() call to send () the data again. Można też umieścić pętlę z funkcją sleep () i wywołanie send (), ale trzeba zadbać o liczbę bajtów faktycznie wysłanych i pozostałą liczbę bajtów, które mają zostać wysłane.

 1
Author: Sumit Trehan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-02 07:50:30

Czy to oznacza, że wywołanie send() zawsze powróci natychmiast, jeśli jest miejsce w jądrze wyślij bufor?

Nie powinno? Moment, po którym dane "są wysyłane" można zdefiniować w różny sposób. Myślę, że jest to moment, w którym OS zaakceptował Twoje dane do dostarczenia na stosie. Inaczej jest to dość trudne do zdefiniowania. Czy jest to moment, kiedy dane są przesyłane do bufora karty sieciowej? Lub po chwili wypchnięcia danych z karty sieciowej bufor?

Czy Jest jakiś problem, który musisz wiedzieć na pewno, czy jesteś po prostu ciekawy?

 0
Author: Vladislav Rastrusny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 15:21:06

Twoje domniemanie jest poprawne. Jeśli w buforze wysyłania jądra jest miejsce, jądro skopiuje dane do bufora wysyłania i send() powróci.

 0
Author: caf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-24 00:48:12