Программирование на C — Понимание bind()

У меня возникли проблемы с пониманием функции bind() в отношении сокетов домена Unix.

address.sun_family = AF_UNIX;
addrlen = sizeof(address.sun_family) + strlen(SOCK_PATH);
.
.
.
bind(socket_fd, (struct sockaddr *) &address, addrlen) != 0) 

Как я понимаю в настоящее время, это берет socket_fd (расположенный в пространстве имен процессов), который был создан с помощью socket(), и «применяет» адресную информацию, содержащуюся в адресе, к сокету. По сути, создать его, чтобы другие процессы могли его использовать... Я думаю, что это правильно.

Чего я не понимаю, так это необходимости аргумента addrlen. Это длина структуры адреса без начальных/конечных нулевых байтов. Правильный? Необходим ли этот аргумент, чтобы сообщить bind(), сколько байтов нужно прочитать из адреса???

Спасибо за ваше понимание!


person C_p678    schedule 25.07.2011    source источник


Ответы (3)


Проще говоря, bind говорит системе: okay, from now on, any packet with destination {address->sun_addr} should be forwarded to my socket_fd, so I can read them.

Аргумент addrlen указывает размер структуры, поскольку могут передаваться структуры разных типов (разных размеров). Например, struct sockaddr_un*, struct sockaddr_in*. Вместо этого передается "общая" структура, struct sockaddr*, поэтому bind не знает, каков реальный тип вашей структуры. Вот почему вы должны передать длину.

PS: я уверен, что вы имели в виду адресное пространство процесса, а не пространство имен процесса.

person user703016    schedule 25.07.2011

Не уверен, почему ваш addrlen настроен так, правильный/обычный метод:

   memset(&addr, 0, sizeof(struct sockaddr_un));
                        /* Clear structure */
   addr.sun_family = AF_UNIX;
   strncpy(addr.sun_path, MY_SOCK_PATH,
            sizeof(addr.sun_path) - 1);

   if (bind(sfd, (struct sockaddr *) &addr,
            sizeof(struct sockaddr_un)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
   }

обратите внимание на использование sizeof(), не ожидается strlen/addrlen

person KevinDTimm    schedule 25.07.2011
comment
Хорошо... но мне нужен &addrlen в качестве третьего аргумента неизбежной функции accept(). Так почему бы мне не использовать его как в bind(), так и в accept()? - person C_p678; 25.07.2011
comment
значение то же самое (так что его можно установить), но вы устанавливаете его недопустимо независимо (сделано правильно, это addrlen = sizeof (struct sockaddr_un);, если вы используете ту же структуру сокета) - person KevinDTimm; 25.07.2011
comment
В случае accept addrlen является одновременно и входом, и выходом — вы указываете размер буфера, который вы передаете, и ядро ​​​​сообщает вам, насколько велик sockaddr, который к вам подключается. - person Chris Dodd; 25.07.2011
comment
Хорошо, размер структуры sockaddr_un равен 110. sockaddr_un.sun_family равен 1 (+ один нулевой байт) = 2, а sockaddr_un.sun_path равен 107 (+ один нулевой байт) = 108. 2 + 108 = 110. Верно??? - person C_p678; 25.07.2011
comment
так же, как я закодировал это выше, используйте sizeof() - не делайте ничего другого, так как вы будете неприятно удивлены такими вещами, как выравнивание элементов и т. д. (также см. ответ от Cicada ниже) - person KevinDTimm; 25.07.2011

Я также все еще учусь, это то, что привело меня сюда, поэтому, возможно, объяснение моего понимания поможет мне учиться, так что будьте утомлены, я могу быть очень неправ, или я могу быть в правильном направлении...

Вам это нужно, потому что адреса IPv4 и IPv6 имеют разную длину, как и адреса разных протоколов, я предполагаю, что не все протоколы, такие как Apple Talk или протоколы Ham Radio, используют адреса, напоминающие адреса в стиле IPv4, которые представляют собой набор из 4 байтов, октетов Я думаю, что они называются, разделенные «.».

Поэтому, когда вы вызываете «sizeof(struct sockaddr_in)», вы передаете «int», то есть количество байтов, из которых состоит sockaddr_in, что будет отличаться от «sizeof(struct sockaddr_in6)» sizeof(struct sockaddr_un). sockaddr_in — для inet или IPv4, *_in6 — для inet6 или IPv6, а *_un — для сокетов домена Unix. Я считаю, что адреса сокетов домена Unix — это пути к файлам, которые можно использовать только для локальной связи процессов. Итак, во-первых, функция/метод должны знать, где находится файл сокета, например, /home/user/Pictures/socket, чтобы он мог привязать его к локальному порту, отсюда и дело strncopy и sun_path. Это также может относиться к сокетам inet/6, винсоки могут отличаться. (Изучение C/C++ в Windows было самым близким к самоубийству, которое я когда-либо испытывал).

Целое число, которое передается через «sizeof(struct sockaddr_un)», может использоваться для определения режима выполнения в фактическом коде реализации. если arg[2] = N, сделайте это;иначе, если arg[2] = M, сделайте это???Может быть...

Если вы прочтете руководство по сокетам, то увидите, что в примере используется «sizeof()», а не addrlen.

Примечание. При достижении размера в байтах адресной структуры вашего протокола не имеет значения, действительно ли структура, которую вы используете, содержит полезные данные, вам просто нужен ее размер, поэтому структура создается в параметре, используя «sizeof ( )" во вновь созданной структуре возвращает нужный вам тип int, и это то, что используется в качестве аргумента для третьего параметра.

person Overloaded_Operator    schedule 23.12.2013