Я получил ошибку во время выполнения, что "Невозможно назначить запрошенный адрес" в C под Linux (Centos) - PullRequest
8 голосов
/ 10 января 2012

Когда я присваиваю этот адрес, он говорит cannot assign requested address.Но когда я ставлю локальный адрес (127.0.0.1), он принимает его.Почему ???

char* hostname = "192.168.1.8"; 

int sockfd;
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t addr_len;
int numbytes;
char buf[MAXBUFLEN];
int port =5000;

if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    perror("socket");
    exit(1);
}
try
{
    my_addr.sin_family = AF_INET;        // host byte order
    my_addr.sin_addr.s_addr = inet_addr(hostname);

    printf("Accepted/n");
    // automatically fill with my IP
    my_addr.sin_port = htons(5000);  // short, network byte order
    memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    {
        perror("bind");
        exit(1);
    }
    while (1)
    {
        addr_len = sizeof(struct sockaddr);
        if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
            (struct sockaddr *)&their_addr, &addr_len)) == -1) {
            perror("recvfrom");
            exit(1);
        }

        //printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));
        //printf("packet is %d bytes long\n",numbytes);
        buf[numbytes] = '\0';
       //printf("packet contains \"%s\"\n",buf);
    }

    close(sockfd);
}
catch(...)
{

1 Ответ

14 голосов
/ 10 января 2012

Если ошибка возникает на bind (это не так очевидно по содержанию вашего вопроса, так как сообщение об ошибке, которое вы указали, не появляется в коде), скорее всего, это связано с тем, что адрес недоступен.

Обычно это происходит потому, что он уже используется или недоступен на текущем хосте.

За некоторыми исключениями, вы, как правило, можете связывать только IP-адреса, назначенные локальным интерфейсам.Вы должны проверить, что 192.168.1.8 находится в этом классе.Принято считать, что 127.0.0.1 будет локальным интерфейсом (следовательно, почему он работает), и что INADDR_ANY также будет работать - это, вероятно, «адрес», который вы должны использовать, если у вас нет реальной конкретной необходимости ограничивать себя одниминтерфейс.

Вы должны проверить errno после сбойной функции и сопоставить ее с возможностями .


В сторону, и это, вероятно, не имеет значенияк вашей проблеме, способ инициализации структуры sockaddr_in (установка полей, а затем очистка остальных) кажется мне менее чем переносимым.

Я думаю, что было бы безопаснее очистить лот, чем простоустановите желаемое после этого, что-то вроде:

memset (&my_addr, 0, sizeof (my_addr));
my_addr.sin_family      = AF_INET;
my_addr.sin_addr.s_addr = inet_addr (hostname);
my_addr.sin_port        = htons (5000);

По крайней мере, порядок полей в структуре не повлияет на ваш код.


Вы можете видетьпроблема со следующим кодом.Прежде всего, необходимые заголовки:

#define __USE_GNU
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

Затем проверка аргументов и создание сокетов.

int main (int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in me;

    if (argc < 2) {
        printf ("Need argument with IP address\n");
        return 1;
    }

    if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return 1;
    }

Затем сама привязка:

    memset (&me, 0, sizeof (me));
    me.sin_family = AF_INET;
    me.sin_addr.s_addr = inet_addr (argv[1]);
    me.sin_port = htons (5000);

    if (bind (sockfd, (struct sockaddr *)&me, sizeof(struct sockaddr)) == -1)
    {
        fprintf (stderr, "errno = %d ", errno);
        perror("bind");
        exit(1);
    }

    close(sockfd);

    return 0;
}

Когда вы запускаетечто с определенными аргументами вы можете видеть, что это работает нормально для тех, где IP-адреса принадлежат локальным интерфейсам (127.0.0.1 и 192.168.0.101), но не для тех, которые этого не делают, например 192.168.0.102:

pax> ifconfig | grep 'inet addr'
      inet addr:192.168.0.101  Bcast:192.168.0.255   Mask:255.255.255.0
      inet addr:127.0.0.1                            Mask:255.0.0.0
      inet addr:192.168.99.1   Bcast:192.168.99.255  Mask:255.255.255.0
      inet addr:192.168.72.1   Bcast:192.168.72.255  Mask:255.255.255.0

pax> ./testprog 127.0.0.1

pax> ./testprog 192.168.0.101

pax> ./testprog 192.168.0.102
errno = 99 bind: Cannot assign requested address

pax> grep '#define.*99' /usr/include/asm-generic/errno.h
#define     EADDRNOTAVAIL     99     /* Cannot assign requested address */

И из ссылки на справочную страницу bind выше мы видим:

EADDRNOTAVAIL
Запрошен несуществующий интерфейс или запрошенный адрес не является локальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...