Как узнать локальный IP-адрес адаптера, получившего пакет?
Возникает вопрос "Какой IP-адрес у адаптера приемника?" не адрес отправителя, который мы получаем в
receive_from( ..., &senderAddr, ... );
вызов.





ssize_t
recvfrom(int socket, void *restrict buffer, size_t length, int flags,
struct sockaddr *restrict address, socklen_t *restrict address_len);
ssize_t
recvmsg(int socket, struct msghdr *message, int flags);
[..]
If address is not a null pointer and the socket is not connection-oriented, the
source address of the message is filled in.
Актуальный код:
int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);
fprintf (stdout, «Прочитать% d байтов по локальному адресу% s \ n», nbytes, inet_ntoa (bindaddr.sin_addr.s_addr));
надеюсь это поможет.
Вы можете перечислить все сетевые адаптеры, получить их IP-адреса и сравнить часть, покрываемую маской подсети, с адресом отправителя.
Нравиться:
IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
foreach( adapter in EnumAllNetworkAdapters() )
{
adapterSubnet = adapter.subnetmask & adapter.ipaddress;
senderSubnet = adapter.subnetmask & senderAddr;
if ( adapterSubnet == senderSubnet )
{
return adapter.ipaddress;
}
}
}
Только если пакет исходит из подсети адаптера. Нет, если его направили туда ...
Ага, Лен прав. Если пакет прибыл через NAT на ваш локальный маршрутизатор, вы просто увидите свой локальный IP-адрес (что-то вроде 10.0.0.2).
Разве широковещательные рассылки не маршрутизируются (отправляются только локально)? Таким образом, метод IIRC должен работать.
Это работает для широковещательных рассылок, но широковещательные рассылки - далеко не единственные пакеты, которые может получать сервер. Это не работает для общего случая сервера, имеющего несколько IP-адресов, любой из которых может принимать пакеты из любого места в Интернете.
Доброго времени суток,
Я предполагаю, что вы выполнили привязку с помощью INADDR_ANY для указания адреса.
Если это так, то семантика INADDR_ANY такова, что сокет UDP создается на порту, указанном на всех ваших интерфейсах. Сокет будет получать все пакеты, отправленные на все интерфейсы указанного порта.
При отправке с использованием этого сокета используется интерфейс с наименьшим номером. В поле адреса исходящего отправителя устанавливается IP-адрес того первого используемого исходящего интерфейса.
Первый исходящий интерфейс определяется как последовательность при выполнении команды ifconfig -a. Вероятно, это будет eth0.
HTH.
ваше здоровье, Роб
Решение, предоставляемое тимбо, предполагает, что диапазоны адресов уникальны и не перекрываются. Хотя это обычно так, это не универсальное решение.
В книге Стивена «Сетевое программирование Unix» (раздел 20.2) есть отличная реализация функции, которая делает именно то, что вам нужно. Это функция, основанная на recvmsg (), а не на recvfrom (). Если в вашем сокете включена опция IP_RECVIF, то recvmsg () вернет индекс интерфейса, на котором был получен пакет. Затем его можно использовать для поиска адреса назначения.
Исходный код доступен здесь. Речь идет о функции recvfrom_flags ().
Я собираюсь изучить это. Может, это лучшее решение.
Попробуй это:
gethostbyname("localhost");
Это позволит получить только то, что localhost настроено для разрешения (который должен быть 127.0.0.1) .. не принимающий конец пакета UDP.
К сожалению, вызовы API sendto и recvfrom принципиально не работают при использовании сокетов, привязанных к «Any IP», потому что у них нет поля для информации о локальном IP.
Итак, что вы можете с этим поделать?
Ни один из этих вариантов не хорош. Очевидно, что угадывание всегда приводит к неправильным ответам. Связывание отдельных сокетов увеличивает сложность вашего программного обеспечения и вызывает проблемы, если список локальных адресов изменяется во время работы вашей программы. Новые API-интерфейсы являются правильным техническим решением, но могут снизить переносимость (в частности, похоже, что WSArecvmsg недоступен в Windows XP) и могут потребовать изменений в используемой вами библиотеке-оболочке сокета.
Правка выглядит так, как будто я ошибался, кажется, что документация MS вводит в заблуждение и что WSArecvmsg доступен в Windows XP. См. https://stackoverflow.com/a/37334943/5083516
вы можете сначала установить SO_REUSEADDR в значение true
BOOL bOptVal = 1;
setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
после receive_from( ..., &remoteAddr, ... ); создайте еще один сокет и снова подключитесь к remoteAddr. Затем вызовите getsockname и получите IP-адрес.
SOCKET skNew = socket( )
// Same local address and port as that of your first socket
// INADDR_ANY
bind(skNew, , )
// set SO_REUSEADDR to true again
setsockopt(skNew, SOL_SOCKET, SO_REUSEADDR, (char *)&boOptVal, sizeof(bOptVal));
// connect back
connect(skNew, remoteAddr)
// get local address of the socket
getsocketname(skNew, )
исходный адрес - это удаленный адрес