Получение IP-адреса и порта клиента?

Я пишу программу для обмена файлами, и суть ее в том, что есть один главный сервер, к которому подключаются все клиенты. Однако клиенты — это машины, на которых размещены файлы, поэтому, когда один клиент запрашивает файл у другого, он должен создать с ним соединение. Когда клиент изначально подключается к основному серверу, я получаю его IP и порт (я думаю) с помощью:

    int client_len = sizeof(client);
    int new_sd = accept(sd, (struct sockaddr *)&client, &client_len);

    char str[INET_ADDRSTRLEN]; 
    inet_ntop(AF_INET, &(client.sin_addr), str, INET_ADDRSTRLEN);
    //printf("%s\n", str);
    int port = (int) ntohs(client.sin_port);        
    //printf("Port is: %d\n", (int) ntohs(client.sin_port));

Printf дает мне 127.0.0.1 и 40XXX. Основной сервер использует 127.0.0.1 и порт 3000. Поэтому я почти уверен, что у меня правильный IP-адрес и порт клиента, НО когда я пытаюсь установить соединение между двумя клиентами, используя 127.0.0.1 и 40XXX, это не работает. Функция подключения продолжает возвращать ошибку. Вот код, пытающийся установить соединение между двумя клиентами:

    if ((cd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "Can't creat a socket\n");
        exit(1);
    }
    bzero((char *)&cServer, sizeof(struct sockaddr_in));
    cServer.sin_family = AF_INET;
    cServer.sin_port = htons(cPort);
    if (inet_pton(AF_INET, cAddress, &cServer.sin_addr) == -1) {
        printf("inet_pton error occured\n");
        exit(1);
    } 

    /* Connecting to the server */
    if (connect(cd, (struct sockaddr *)&cServer, sizeof(cServer)) == -1) {
        fprintf(stderr, "Can't connect to server\n");
        exit(1);
    }

cPort — это int, а cAddress — это массив символов.

Вот код от клиента, пытающегося создать соединение для входящих соединений. Код для получения IP-адреса и порта возвращает 0.0.0.0 и 0 соответственно.

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "Can't creat a socket\n");
    exit(1);
}

/* Bind an address to the socket    */
bzero((char *)&clientServer, sizeof(struct sockaddr_in));
clientServer.sin_family = AF_INET;
clientServer.sin_port = 0;
clientServer.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&clientServer, sizeof(clientServer)) == -1){
    fprintf(stderr, "Can't bind name to socket\n");
    exit(1);
}

char str[INET_ADDRSTRLEN]; 
inet_ntop(AF_INET, &(clientServer.sin_addr), str, INET_ADDRSTRLEN);
printf("%s\n", str);
int clientServerPort = (int) ntohs(clientServer.sin_port);      
printf("Port is: %d\n", (int) ntohs(client.sin_port));

/* queue up to 10 connect requests  */
listen(sockfd, 10);

Вся помощь очень ценится!


person user2929779    schedule 02.11.2014    source источник


Ответы (2)


Вы не можете использовать клиентский порт для нового подключения. Этот порт используется только для подключения к вашему серверу, он не прослушивает входящие подключения. Клиент должен привязать другой порт, прослушать его и отправить вам этот номер порта. Затем вы можете отправить его другому клиенту, и он сможет подключиться к порту.

Также обратите внимание, что это может вообще не работать, если первый клиент находится за NAT-маршрутизатором. Маршрутизатор не будет знать, что он должен переадресовать этот новый порт клиенту. Одноранговые приложения с динамическими номерами портов непрактичны, когда используется NAT. Вместо этого вы должны определить выделенный порт для этой цели; затем пользователи могут настроить переадресацию портов на своих маршрутизаторах для этого порта.

person Barmar    schedule 02.11.2014
comment
Это то, что я изначально пробовал. Используя тот же код выше, чтобы получить IP-адрес и номер порта после привязки, но он вернул 0.0.0.0 и 0. Я обновил свой основной пост. Также повлияет ли на меня маршрутизатор NAT, даже если я строго придерживаюсь локальных IP-адресов? - person user2929779; 02.11.2014
comment
NAT - это проблема, только если вы проходите через маршрутизатор. Если все машины находятся за маршрутизатором, это не проблема. - person Barmar; 02.11.2014
comment
Вам нужно вызвать getsockname(), чтобы получить IP-адрес и порт, назначенные сокету bind(). stackoverflow.com/questions/10167540/ - person Barmar; 02.11.2014

Это то, что я изначально пробовал. Используя тот же код выше, чтобы получить IP-адрес и номер порта после привязки, но он вернул 0.0.0.0 и 0. Я обновил свой основной пост. Также повлияет ли на меня маршрутизатор NAT, даже если я строго придерживаюсь локальных IP-адресов?

Проблема с несколькими интерфейсами. Сделайте ifconfig -a, найдите нужный интерфейс.

person Mahesh Karoshi    schedule 14.12.2020
comment
Не уверен, есть ли у вас права комментировать как новый пользователь, но в будущем это будет более уместно в качестве комментария к вопросу, а не ответа. - person Michael Wu; 14.12.2020