Как получить IP-адрес, используемый для подключения к моему серверу? - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть сервер, прослушивающий несколько устройств (LAN, WiFi и, возможно, некоторые VPN).

Прослушивание привязывает сокет (AF_INET), привязывает INADDR_ANY для показа на всех интерфейсах.

Затем клиент подключается и начинается обмен.

На этом этапе, как я могу получить информацию о том, какое устройство использовалось для подключения?

Эквивалентно: как я могу получить IP-адрес, используемый клиентом дляconnect?

EDIT: Следуя совету @Barmar, я попробовал следующее:

#include <sys/socket.h>
#include <netinet/ip.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

void error(char *msg)
{
    perror(msg);
    exit(1);
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno;
    unsigned clilen;
    struct sockaddr_in serv_addr, cli_addr;
    struct sockaddr_in myaddr;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        error("ERROR creating socket");
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 5666;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
        error("ERROR on binding");
    listen(sockfd, 5);
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0)
        error("ERROR on accept");

    clilen = sizeof(myaddr);
    if (getsockname(newsockfd, (struct sockaddr *)&myaddr, &clilen))
        error("ERROR in getsockname");

    unsigned int i = myaddr.sin_addr.s_addr;
    int p = myaddr.sin_port;
    int a = i & 0xff;
    i >>= 8;
    int b = i & 0xff;
    i >>= 8;
    int c = i & 0xff;
    i >>= 8;
    int d = i & 0xff;
    printf("my address is: %d.%d.%d.%d:%d\n", a, b,c, d, p);

    return 0;
}

... и (после небольшой отладки) все работает.

Обратите внимание, что порт - это не ожидаемое значение (5666), а последовательно 8726.

1 Ответ

0 голосов
/ 19 сентября 2018

Если вы используете сокет SOCK_STREAM (т. Е. TCP), а не SOCK_DGRAM (т. Е. UDP), вызовите getsockname() на сокете, возвращаемом accept().

Если вы используете сокет датаграммы, я не думаю, что есть портативный способ сделать это с одним сокетом.Традиционным решением является привязка отдельного сокета для каждого локального адреса вместо использования INADDR_ANY и ожидание сообщения на всех из них с использованием epoll() или select().Вы можете определить, к какому адресу они подключены, в зависимости от того, по какому сокету было получено сообщение.

В Linux и Windows есть расширение, которое позволяет вам сделать это проще, установив параметр IP_PKTINFO в сокете ииспользуя recvmsg() для получения пакета.В msgheader.msg_control вы можете получить адрес получателя пакета.См. Получение адреса назначения полученного пакета UDP

.
...