Когда клиентский сокет должен быть привязан для получения UDP-сообщений от сервера? - PullRequest
2 голосов
/ 01 августа 2011

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

Пример 1:

код сервера http://man7.org/tlpi/code/online/book/sockets/ud_ucase_sv.c.html

код клиента http://man7.org/tlpi/code/online/book/sockets/ud_ucase_cl.c.html

Клиентская программа создает сокет и привязывает сокет к адресу, чтобы сервер мог отправить свой ответ.

if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
    errExit("bind"); // snippet from ud_ucase_cl.c

Пример 2:

код сервераhttp://man7.org/tlpi/code/online/book/sockets/i6d_ucase_sv.c.html

код клиента http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_cl.c.html

В примере 2 код клиента не связывает свой сокет с адресом.

Вопрос :

Необходимо ли клиентскому коду связывать сокет с адресом для получения сообщения от сервера?

Почему в первом примере мынужно связать клиентский сокет с адресом, почему нам не нужно во втором примере?

Ответы [ 3 ]

1 голос
/ 01 августа 2011

Разница составляет socket family - в первом примере используется AF_UNIX, а во втором - AF_INET6.Согласно Stevens UNP вам необходимо явно bind путь к клиентскому сокету Unix, чтобы у сервера был путь к которому он может отправить свой ответ:

... отправка дейтаграммы внесвязанный сокет дейтаграммы домена Unix неявно привязывает путь к сокету.Поэтому, если мы пропустим этот шаг, серверный вызов recvfrom ... вернет нулевой путь ...

Это не требуется для сокетов INET{4,6}, так как они "автоматически связаны" сэфемерный порт.

1 голос
/ 01 августа 2011

Если вы не связали клиентский сокет AF_INET / AF_INET6 перед подключением / отправкой чего-либо, стек TCP / IP автоматически связывает его с эфемерным портом на исходящем адресе.

В отличие от этого, доменные сокеты UNIX (AF_UNIX) не связываются автоматически при отправке, поэтому вы можете отправлять сообщения через SOCK_DGRAM, но не можете получать ответы.

1 голос
/ 01 августа 2011

Для клиента (TCP) или отправителя (UDP) вызов bind() не является обязательным; это способ указать интерфейс. Предположим, у вас есть два интерфейса, оба из которых маршрутизируются к месту назначения:

eth0: 10.1.1.100/24
eth1: 10.2.2.100/24

route: 10.1.1.0/24 via 10.2.2.254  # router for eth1
       0.0.0.0     via 10.1.1.254  # general router

Теперь, если вы просто скажете от connect() до 12.34.56.78, вы не знаете, какой локальный интерфейс обеспечивает локальную сторону соединения. Позвонив сначала по номеру bind(), вы сделаете это конкретно.

То же самое верно для UDP-трафика: без bind() ing ваш sendto() будет использовать случайный адрес источника и порт, но с bind() вы сделаете источник специфичным.

...