2013-04-10 9 views
7

私のプログラムが起動されたコンピュータのIPアドレスを取得してクライアントに送信できるようにしたいのですが、実際のIPアドレス(たとえば127.0.0.1など)ではなく常に0.0.0.1を取得します。 。ソケットアドレスで独自のIPアドレスを取得するには?

現在、ポートは取得できますが、IPアドレスは取得できません。

どうすれば入手できますか?

最高の解決策は、sockaddr_inで入手できるようにすることです。ここで私が現在やっているものです:

int open_connection(char* ip, int* port) 
{ 
    int     sock; 
    struct sockaddr_in sin; 
    socklen_t    len; 
    int     i; 

    i = 0; 
    len = sizeof(sin); 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
    return (-1); 
    bzero(&sin, sizeof(struct sockaddr_in)); 
    sin.sin_family = AF_INET; 
    if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) 
    perror("Error on bind"); 
    if (getsockname(sock, (struct sockaddr *)&sin, &len) != 0) 
    perror("Error on getsockname"); 
    strcpy(ip, inet_ntoa(sin.sin_addr)); // IP = 0.0.0.0 
    *port = sin.sin_port; 
    return (sock); 
} 

EDIT:私は思考の私の方法で間違った方向に行っていた理解しています。だから私の質問です:自分のIPアドレスを取得する最良の方法は何ですか?

+1

クライアントがあなたと話している場合、彼はすでにあなたのIPアドレスを持っています。私はなぜそれを明示的に送る必要があるのか​​混乱しています。 – Pyrce

+1

@Pyrce私はFTPサーバーを作っています。パッシブモードに入ると、サーバーが聞いているIPアドレスとポートを送信する必要があります...同じIPアドレスであっても... –

+2

多分この古い質問? http://stackoverflow.com/questions/212528/get-the-ip-address-of-the-machine私は0.0.0.0へのバインドは、すべてのIPアドレスでバインドを意味する特定のものだと思う - 私はあなたを疑う – Rup

答えて

10

bind()ソケットを0.0.0.0に設定すると、ソケットはgetsockname()を呼び出すときに使用できる唯一のIPです。これは、ソケットがすべてのローカルインタフェースにバインドされていることを意味します。特定のIPをソケットから取得するには、特定のIPにバインドする必要があります。

マシンのローカルIPを取得するためにソケットAPIを使用する方法は間違っています。一般的な間違いはgethostname()gethostbyname()またはgetaddrinfo()を使用してローカルIPリストを取得することです。通常は動作しますが、誤った情報を引き起こす可能性のある隠された邪魔をしていますが、人々はその事実を無視する傾向があります。あるいは、最初にそれについて知ることさえしません(私は何年もそれを知りませんでした。より良く学んだ)。

代わりに、プラットフォーム固有のAPIを使用して、ローカルネットワークインターフェイスを列挙する必要があります。それはより信頼性の高い情報を提供します。 WindowsにはGetAdaptersInfo()GetAdaptersAddresses()があります。他のプラットフォームはgetifaddrs()です。それらは、どのローカルIPが利用可能であるかを伝えます。 bind()これらのIPのいずれかでクライアントを受け入れるには0.0.0.0へのソケットを、特定のIPにはbind()を指定すると、そのIP上でのみクライアントを受け入れることができます。

+0

getaddrinfo()の "* ... hidden gotchas ... *"について詳しく説明できますか? – alk

+0

'gethostbyname()'と 'getaddrinfo()'は、ホスト名をIPに解決するためにDNSルックアップを使うように設計されています。彼らはlocalhostに関する情報を取得するためのものではありません。 a)ユーザーがOSのDNSキャッシュ(ホストファイルなど)を変更/破損する可能性があり、b)PCのホスト名がIPをまったく持たないか、またはすべてではないかもしれない複数のIPにマップするように構成するPCに(負荷分散などを考える)。これらの関数は、すべての設定でローカルホスト名が渡されたときに、有効なローカルIPを返すことは100%保証されていません。 'GetAdaptersInfo()'や 'getifsaddrs()'のような関数はその目的のために設計されています。 –

+0

ああ、**外部** DNSはあなたが基本的に言っているものです。私はこれに同意する。明確化のためにありがとう。 – alk

4

ソケットAPIを使用すると、ネットワークインターフェイスに割り当てられたIPアドレスを列挙できますが、ルーターの背後からインターネットに接続している場合は、「実際のIP」が何であるかはわかりません。

それを知る唯一の方法は、誰かに尋ねることです。それで、FileZilla FTP Serverのようなサーバーがそうしているのです。彼らはサーバの設定でthis oneのような "ip.php"スクリプトへのURLを設定して、パッシブモードで使うためにパブリックIPアドレスをインターネットに尋ねるように指示します。

公衆IPを検出するためにVoIPで広く使用されているプロトコルのSTUNを使用することも考えられます。

+1

+1。 OPがより多くのオプションを望む場合、私は個人的に[ifconfig.me](http://ifconfig.me)、[canhazip.com](http://canhazip.com)が好きです。 – jweyrich

+0

ありがとう、それは私の現在のニーズに適応していません(それは学校のプロジェクトであり、インターネットからは動作しません)。私はそれを実装する時間があるかどうかがわかります。 –

0

あなたはioctlを呼び出すことができます(靴下、SIOCGIFADDRを、ADR)

は、私は、現在のマシンのアドレスを返す機能を書いた@Remy Lebeauの答えに続きnetdevice(7)

0

を参照してください。私はmacOS High Sierraでこれをテストしただけです。

interfaecAF_INETAF_INET6ことができるなど

ipVersionlo0の中では何も、en0をすることができます。私に教えてください何か問題がある場合は、それを使用するには

long int getInternalAddress(char* interface, sa_family_t ipVersion) 
{ 
    struct ifaddrs *ifaddrHead, *ifaddr; 
    /* int_8 */ 
    sa_family_t family; 
    int n; 
    char *interfaceName; 

    if (getifaddrs(&ifaddrHead) != 0) 
    { 
    fprintf(stderr, "ifaddrs error"); 
    } 

    /* iterate through address list */ 
    for (ifaddr = ifaddrHead, n = 0; ifaddr != NULL; ifaddr = ifaddr->ifa_next, n++) 
    { 
    family = ifaddr->ifa_addr->sa_family; 
    interfaceName = ifaddr->ifa_name; 

    if (!family || family != ipVersion || strcmp(interfaceName, interface)) continue; 

    struct sockaddr *addr = ifaddr->ifa_addr; 
    struct sockaddr_in* addr_in = (struct sockaddr_in*) addr; 
    long int address = addr_in->sin_addr.s_addr; 

    freeifaddrs(ifaddrHead); 

    return address; 
    } 

    freeifaddrs(ifaddrHead); 

    return 0; 
} 

int main() 
{ 
    long int address = getInternalAddress((char*) &"en0", AF_INET); 
    printf("%li\n", address); 

    return 0; 
} 

私は、まだCで初心者です。