Странное поведение сокетов Linux - PullRequest
2 голосов
/ 08 сентября 2011

Меня немного смущает разница между определениями протоколов в Linux при использовании socket().Я пытаюсь прослушивать соединения через TCP, используя socket(PF_INET, SOCK_STREAM, proto), где proto (на мой взгляд) оспаривается или, по крайней мере, кажется странным.

От <netinet/in.h>:

...
IPPROTO_IP = 0,    /* Dummy protocol for TCP.  */
...
IPPROTO_TCP = 6,       /* Transmission Control Protocol.  */
...

Согласовано с /etc/protocols:

ip      0       IP              # internet protocol, pseudo protocol number
hopopt  0       HOPOPT          # hop-by-hop options for ipv6
...
tcp     6       TCP             # transmission control protocol
...

Я узнал из онлайн-учебника, а также со страницы руководства tcp(7), что вы инициализируете сокет TCP с помощью

tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

, который работает абсолютно нормально, и, конечно, является сокетом TCP.Одна из особенностей использования приведенных выше аргументов для инициализации сокета состоит в том, что код

struct timeval timeout = {1, 0};
setsockopt(tcp_socket, 0, SO_RCVTIMEO, &timeout, sizeof(timeout); // 1s timeout
// Exactly the same for SO_SNDTIMEO here

работает абсолютно нормально, но не после замены всех аргументов протокола (включая socket()) на IPPROTO_TCP, в отличие от IPPROTO_IP, который у них есть, как указано выше.

Итак, после эксперимента с разницей, мне нужно было задать несколько вопросов для поиска:

  1. ПочемуКогда я заменяю все аргументы протокола на IPPROTO_TCP, выдается ли ошибка 92 («Протокол недоступен») при установке тайм-аутов, когда протокол 0, по-видимому, является просто «фиктивным» TCP?
  2. Почему socket() требуется информация о том, должен ли это быть поток, датаграмма или необработанный сокет, когда эта информация (всегда?) неявно известна из протокола, и наоборот?(т. е. TCP - это потоковый протокол, UDP - это протокол датаграмм, ...)
  3. Что может означать «фиктивный TCP»?
  4. Что такое hopopt и почемуУ вас такой же номер протокола, как у 'ip'?

Большое спасибо.

Ответы [ 2 ]

3 голосов
/ 08 сентября 2011

Предоставление 0 в качестве протокола для socket просто означает, что вы хотите использовать протокол по умолчанию для пары семейство / тип носка. В этом случае это TCP, и, таким образом, вы получите тот же результат, что и с IPPROTO_TCP.

Ваша ошибка в вызове setsockopt. Правильный будет

setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // 1s timeout

0 там не для протокола, а для уровня опции. IPPROTO_TCP - это еще один уровень опции, но вы не можете комбинировать это с SO_RCVTIMEO. Может использоваться только вместе с SOL_SOCKET. Те, которые вы используете с IPPROTO_TCP, перечислены в tcp (7), например TCP_NODELAY.

2 голосов
/ 08 сентября 2011

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); должно работать нормально.

Передача 0 в качестве протокола просто означает, дайте мне значение по умолчанию.Который в каждой системе является TCP для потоковых сокетов и UDP для дейтаграммы, когда имеешь дело с IP.Но socket () может использоваться для многих других целей, давая вам сокет TCP или UDP.

socket () довольно общий характер.socket(AF_INET, SOCK_STREAM, 0); просто читается как;msgstr "дай мне потоковый сокет в семействе протоколов IP".Передача 0 означает, что у вас нет предпочтений по какому протоколу - хотя TCP является очевидным выбором для любой системы.Но теоретически это могло бы дать вам, например, сокет SCTP.

Если вы хотите, чтобы датаграмма или потоковые сокеты были не неявными для протоколов.Существует намного больше протоколов, исключающих протоколы на основе IP, и многие из них можно использовать либо в дейтаграмме, либо в режиме потоковой передачи, например SCCP, который используется в сетях SS7.

Для протоколов на основе IP SCTP может использоваться в виде дейтаграммы или потоковой передачи.Таким образом сокет (AF_INET, IPPROTO_SCTP);было бы неоднозначно.А для сокетов дейтаграмм есть и другие варианты: UDP, DCCP, UDPlite.

socket (AF_INET, SOCK_SEQPACKET, 0);еще один интересный выбор.Он не может вернуть сокет TCP, TCP не основан на пакетах.Он не может вернуть и UDP-сокет, UDP не дает гарантии последовательной доставки.Но сокет SCTP подойдет, если система его поддерживает.

У меня нет объяснения, почему кто-то сделал комментарий "фиктивный TCP", так как linux netinet / in.h

опция IPv6 HOP by hop.В IPv6 поле дискриминатора протокола также используется в качестве механизма расширения.В пакетах IPv4 есть поле протокола, которое является дискриминатором протокола, для него будет установлено значение IPPROTO_TCP, если эта дейтаграмма IPv4 содержит TCP.Если этот пакет IPv4 также содержит некоторую дополнительную информацию (опции), они кодируются другими механизмами.

IPv6 делает это иначе, если есть расширение (опция), то это расширение кодируется в поле протокола.Таким образом, если пакет IPv6 нуждается в параметре hop-by-hop, IPPROTO_HOPOPTS помещается в поле протокола.Фактическая опция переход за переходом также имеет дискриминатор протокола, который сигнализирует о том, что является следующим протоколом - который может быть IPPROTO_TCP или еще одна опция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...