web-dev-qa-db-ja.com

Linux(Centos)のCで「要求されたアドレスを割り当てることができません」という実行時にエラーが発生しました

このアドレスを割り当てると、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(...)
{
9
gaurav bhadani

bindでエラーが発生している場合(指定したエラーメッセージがコードに表示されないため、質問の内容からするとそれほど明白ではありません)、アドレスが利用できないことが原因である可能性があります。

これは通常、すでに使用されているか、現在のホストで使用できないためです。

いくつかの例外を除いて、通常はローカルインターフェイスに割り当てられているIPアドレスにのみバインドできます。 192.168.1.8がそのクラスに含まれていることを確認する必要があります。 127.0.0.1がローカルインターフェイスになり(したがって、それが機能する理由)、INADDR_ANYも同様に機能することは当然のことです。これは、1つのインターフェイスに制限する必要がない限り、おそらく使用する必要のある「アドレス」です。

失敗した関数に続く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
存在しないインターフェースがリクエストされたか、リクエストされたアドレスがローカルではありませんでした。

15
paxdiablo