Я установил сокет UDP с тем же удаленным адресом в диапазоне многоадресной рассылки. Один отправляет на 224.2.0.6:6666, другой на 224.2.0.7:6666. Я полагаюсь на таблицу маршрутизации Linux, чтобы определить, через какой интерфейс отправлять пакеты.
В обоих случаях я устанавливаю сокет в начале, устанавливаю свои сокеты и делаю sendto()
. Я не устанавливаю конкретный IP_MULTICAST_IF
.
Однако в первом случае я также делаю connect()
перед первым sendto()
.
В случае connect()
ОС игнорирует петлевой маршрут и отправляет все пакеты через маршрут и интерфейс по умолчанию.
В случае, отличном от connect()
, ОС учитывает петлевой маршрут, и все пакеты отправляются через петлевой интерфейс.
Почему socket()
-connect()
-sendto()
с маршрутом через lo
заставляет ОС игнорировать его, в то время как просто выполнение socket()
-sendto()
с маршрутом через lo
маршрутизируется правильно?
My ip route
:
224.2.0.0/16 via 127.0.0.1 dev lo
default via 172.16.5.1 dev eth0
Обратите внимание, что эта проблема возникает только, если маршрут идет к петлевому интерфейсу. Если я устанавливаю маршрут через «настоящий» интерфейс — фактический, macvlan, фиктивный, что угодно, — тогда и connect()
, и sendto()
одинаково учитывают маршрут и работают нормально.
ОБНОВИТЬ:
Оригинальный код. Форматирование было перепутано, так как это была правка чужого кода, пытался почистить вручную, извиняюсь за беспорядок:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdlib.h>
int fd, fd2;
struct in_addr interface_addr;
int addr_size;
int optval = 1, recv_len = 4;
char *remote_ip = "224.2.0.6", *remote_ip2 = "224.2.0.7";
char *remote_port = "6666";
char *buf = "conn", *buf2 = "send";
struct addrinfo *remote_address_info, *remote_address_info2;
int main() {
// create first and second socket
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket() failed");
}
if ((fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket2() failed");
}
// set socket options on both
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
}
if (setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
perror("setsockopt2(SO_REUSEADDR) failed");
}
addr_size = sizeof(interface_addr);
// structure the addr
if (getaddrinfo(remote_ip, remote_port, NULL, &remote_address_info) != 0) {
perror("getaddrinfo(remote_ip) failed");
}
if (getaddrinfo(remote_ip2, remote_port, NULL, &remote_address_info2) != 0) {
perror("getaddrinfo2(remote_ip) failed");
}
// connect ON FIRST SOCKET ONLY
if (connect(fd, remote_address_info->ai_addr, remote_address_info->ai_addrlen) != 0) {
perror("connect() failed");
}
// sendto first and second
// same result if use send() or sendto() on first socket
if (sendto(fd, buf, recv_len, 0, remote_address_info->ai_addr, remote_address_info->ai_addrlen) == -1) {
perror("sendto() failed");
}
if (sendto(fd2, buf2, recv_len, 0, remote_address_info2->ai_addr, remote_address_info2->ai_addrlen) == -1) {
perror("sendto2() failed");
}
}