Вопрос или проблема
У меня несколько сетевых интерфейсов на моем компьютере с Ubuntu.
======================
ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:caff:fe8e:4751 prefixlen 64 scopeid 0x20<link>
ether 02:42:ca:8e:47:51 txqueuelen 0 (Ethernet)
RX пакеты 765284 байты 41062277 (41.0 MB)
RX ошибки 0 потеряно 0 превышение 0 фрейм 0
TX пакеты 1184197 байты 5763037228 (5.7 GB)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
eno1np0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.100.105 netmask 255.255.255.0 broadcast 10.10.100.255
ether 3c:ec:ef:74:3b:16 txqueuelen 1000 (Ethernet)
RX пакеты 31185342 байты 31349645842 (31.3 GB)
RX ошибки 0 потеряно 0 превышение 0 фрейм 0
TX пакеты 7674137 байты 1643490885 (1.6 GB)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
eno2np1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 3c:ec:ef:74:3b:17 txqueuelen 1000 (Ethernet)
RX пакеты 0 байты 0 (0.0 B)
RX ошибки 0 потеряно 0 превышение 0 фрейм 0
TX пакеты 0 байты 0 (0.0 B)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
enp175s0f0np0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.0.10 netmask 255.255.0.0 broadcast 172.16.255.255
ether 1c:34:da:7e:65:de txqueuelen 1000 (Ethernet)
RX пакеты 214905696 байты 268542904796 (268.5 GB)
RX ошибки 0 потеряно 0 превышение 0 фрейм 0
TX пакеты 75363 байты 11878888 (11.8 MB)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
enp175s0f1np1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.16.0.11 netmask 255.255.0.0 broadcast 172.16.255.255
ether 1c:34:da:7e:65:df txqueuelen 1000 (Ethernet)
RX пакеты 36352647 байты 40206354758 (40.2 GB)
RX ошибки 0 потеряно 283164 превышение 0 фрейм 0
TX пакеты 998 байты 114081 (114.0 KB)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Локальный цикл)
RX пакеты 3819602 байты 764575236 (764.5 MB)
RX ошибки 0 потеряно 0 превышение 0 фрейм 0
TX пакеты 3819602 байты 764575236 (764.5 MB)
TX ошибки 0 потеряно 0 превышение 0 носитель 0 коллизии 0
======================
Я могу отправлять и получать датаграммы через сокеты UDP. Я использую код подобный этому
https://en.wikipedia.org/wiki/Berkeley_sockets в примерах клиент-сервер UDP.
Мой сервер работает на enp175s0f1np1 172.16.0.11
Я вижу, что мой RX увеличивается на enp175s0f1np1, когда я выполняю ‘watch -n,1 ifconfig’
TX (на любом сетевом интерфейсе) не увеличивается. Не знаю почему, я получаю данные без проблем.
Я думаю, что используется один и тот же сетевой интерфейс enp175s0f1np1 для TX и RX.
Как я могу сделать так, чтобы TX исходил от другого сетевого интерфейса enp175s0f0np0 172.16.0.10 ?
SO_BINDTODEVICE, похоже, предназначен для серверных сокетов, как показано здесь https://unix.stackexchange.com/a/648721/583986
Будет ли это работать и для клиентских сокетов?
Также есть идеи, почему TX не увеличивается, когда я принимаю данные?
Ответ или решение
Для отправки UDP-данных с одного сетевого интерфейса (NIC) и их приема на другом интерфейсе на одном и том же компьютере, необходимо учесть несколько аспектов, включая настройки сокетов и поведение операционной системы с сетевыми интерфейсами.
Настройка окружения
Ваше окружение с различными сетевыми интерфейсами на Ubuntu (eno1np0, eno2np1, enp175s0f0np0, enp175s0f1np1) представлено следующим образом:
- eno1np0: IP – 10.10.100.105
- enp175s0f0np0: IP – 172.16.0.10
- enp175s0f1np1: IP – 172.16.0.11
Судя по вашему описанию, сервер работает на enp175s0f1np1
(IP: 172.16.0.11), и вы хотите отправлять данные с клиента через другой интерфейс enp175s0f0np0
(IP: 172.16.0.10).
Проблема и её анализ
Проблема с TX: Учитывая, что вы отправляете и получаете данные, но TX на интерфейсах не увеличивается, это может означать, что ваш клиент использует ту же NIC (enp175s0f1np1) для отправки, что и сервер. Чтобы переслать данные через интерфейс enp175s0f0np0, стоит явным образом указать, какой интерфейс использовать.
Как отправить UDP-данные через другой NIC
Для этого вы можете использовать SO_BINDTODEVICE
для клиентского сокета, как и для серверного. Этот параметр позволяет связать сокет с конкретным сетевым интерфейсом.
Вот пример кода, который показывает, как это сделать:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <linux/if.h>
#include <sys/ioctl.h>
int main() {
int sock;
struct sockaddr_in server_addr;
char *device = "enp175s0f0np0"; // Название интерфейса
int send_result;
// Создаем UDP сокет
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// Привязываем сокет к интерфейсу
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)) < 0) {
perror("SO_BINDTODEVICE failed");
close(sock);
exit(EXIT_FAILURE);
}
// Настраиваем адрес сервера
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080); // Порт сервера
inet_pton(AF_INET, "172.16.0.11", &server_addr.sin_addr); // IP сервера
// Отправляем данные
const char *msg = "Hello, UDP server!";
send_result = sendto(sock, msg, strlen(msg), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (send_result < 0) {
perror("Send failed");
close(sock);
exit(EXIT_FAILURE);
}
printf("Message sent through %s\n", device);
close(sock);
return 0;
}
Объяснения по коду:
- Создание сокета: Мы начинаем с создания UDP сокета.
- Привязка к интерфейсу: С помощью
setsockopt
иSO_BINDTODEVICE
мы указываем, что этот сокет будет использоваться через интерфейсenp175s0f0np0
. - Настройка адреса сервера: Указываем IP-адрес сервера и порт, на который будем отправлять данные.
- Отправка данных: Используем
sendto
, чтобы отправить сообщения серверу.
Заключение
Используя параметры SO_BINDTODEVICE
, вы сможете успешно отправлять UDP-данные из одного интерфейса, а получать их через другой. Это должно помочь решить вашу текущую проблему и позволить вам управлять маршрутизацией UDP-пакетов на вашем сервере.
Если у вас есть дополнительные вопросы или проблемы, не стесняйтесь обращаться за помощью.