スポンサーリンク

このドキュメントの内容は、以下の通りです。

はじめに

インターネットでは、TCP/IPと呼ばれるプロトコルが使われています。TCP/IPなくして、インターネットは成り立ちません。TCP/IPのIPとは Internet Protocolの略です。

インターネットでは、IPアドレスを利用して通信が行われます。パソコンが通信をするときには、IPアドレスがふられています。家にあるルータにもIPアドレスがわりふられています。

IPアドレスは、人がわかりやすいように、ドット区切りの表記をします。コンピュータの内部では、IPアドレスは、ドット区切りの表記と整数の値の表現を変換して使われていたりします。

多くの方は、あまりIPアドレスを直接見たり、指定したりすることはないと思います。ほとんどの方は、DNSと呼ばれる仕組みを利用していて、IPアドレスが隠蔽されているからです。

現在利用されている IPには、IP バージョン4 (IPv4) と IP バージョン 6 (IPv6)があります。

IPv4のIPアドレスは32ビットであるため、1つの整数で表現されます。

コンピュータの内部で整数のIPアドレスを扱っているときに、人が見てわかりやすいように、ドット区切りの表記のIPアドレスに変換したいことがあるかと思います。ここでは、C言語で整数のIPアドレスをドット区切りのIPアドレスに変換する方法について解説します。

整数のIPからドット区切りのIPアドレスの文字列を取得する方法

C言語で整数のIPアドレスからドット表記のIPアドレス(192.168.0.1みたいなの)の文字列を取得する方法を説明します。

ソケットプログラミングで利用される型のひとつに in_addr_t と呼ばれるものがあります。in_addr_t には、インターネットアドレス、つまりIPアドレスを格納するための変数になります。

ソケットプログラミングで利用されるライブラリの関数の中に、整数のアドレスと文字列のアドレスを変換する関数があります。
ところが、in_addr_t のIPを直接受け取ってくれるinet系の関数がないので in_addr構造体を利用します。in_addr構造体の中身は、in_addr_t だけです。

inet_ntoaのかわりにinet_ntoa_rを使うこともできます。 inet_ntoa_rはinet_ntoaの再入可能(reentrant)バージョンです。
inet_ntoa や inet_aton は、static のバッファを使っていることや IPv6 をサポートしていないため、 inet_ntop や inet_pton を利用したほうが良いでしょう。

inet_ntoaのプロトタイプ


/usr/include/netinet/in.h のヘッダファイルに、以下の関数が定義されています。

char *
inet_ntoa(struct in_addr in);

char *
inet_ntoa_r(struct in_addr in, char *buf, socklen_t size);

inet_ntoa のサンプルプログラム


正の整数のIPアドレスを変換するサンプルプログラムを以下に示します。
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
	unsigned long long_addr = 2085852108ul;
	struct in_addr inaddr = { htonl(long_addr) };
	char *addrstr = inet_ntoa(inaddr);
	if (addrstr) {
		printf ("%s\n", addrstr);
	} else {
		// can not get address
	}
	return 0;
}

inet_ntoa() を見て、気づいたかもしれませんが、 char*型のポインタが返されます。つまり、 inet_ntoa のローカルの static なバッファのアドレスが返されています。inet_ntoa を呼び出したあとに、ほかのアドレスを指定して inet_ntoa を呼び出すと、inet_ntoaのローカルのstatic変数が上書きされてしまいますので、複数回呼び出すときは、注意して利用する必要があります。

コンパイル方法

サンプルプログラムをコンパイルする方法は以下の通りです。
% cc socket.c

実行例

以下がサンプルプログラムの実行例です。
% ./a.out
124.83.147.204

inet_ntoaの実装


inet_ntoa は、 FreeBSD では、 /usr/src/lib/libc/inet/inet_ntoa.c で実装されています。

inet_ntoa は、static なローカル変数にIPアドレスの文字列が格納されて返ってきます。そのため、inet_ntoaを複数回連続して呼び出すような使い方をする場合には、使い方に注意が必要です。マルチスレッドで呼び出すと、おかしなことになるので、使ってはいけません。

inet_ntoa_r は、バッファを渡して、その中に、結果が入ってくるので、複数の呼び出すをする場合にも問題はありません。マルチスレッドでも問題ありません。

inet_ntoa と inet_ntoa_r はともに、 inet_ntop を呼び出します。
inet_ntop は、 FreeBSD では、 /usr/src/lib/libc/inet/inet_ntop.c で実装されています。

inet_ntop 内部では、第1引数のアドレスファミリの指定によって、inet_ntop4やinet_ntop6 が呼び分けられます。

inet_ntop4 は、snprintf で変換しています。
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
int l;
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);

テンポラリのバッファに変換して、最後に strlcpy で指定したバッファに書き込みなおしてます。

テンポラリのバッファの確保のコードは以下のコードです。
char tmp[sizeof "255.255.255.255"];

inet_ntop6 の実装は、 inet_ntop4 に比べるとやや複雑な実装になっています。しかも内部で inet_ntop4 を呼び出していた李します。

もし興味があれば、よく読んでみてください。

まとめ


IPv4 / IPv6 時代では、inet_ntop を利用しましょう。
inet_ntoa は、static なバッファを利用するため、おすすめできません。

inet_ntop のサンプルコードは [2008-11-16-1] をご覧ください。

スポンサーリンク
スポンサーリンク
 
いつもシェア、ありがとうございます!


もっと情報を探しませんか?

関連記事

最近の記事

人気のページ

スポンサーリンク
 

過去ログ

2020 : 01 02 03 04 05 06 07 08 09 10 11 12
2019 : 01 02 03 04 05 06 07 08 09 10 11 12
2018 : 01 02 03 04 05 06 07 08 09 10 11 12
2017 : 01 02 03 04 05 06 07 08 09 10 11 12
2016 : 01 02 03 04 05 06 07 08 09 10 11 12
2015 : 01 02 03 04 05 06 07 08 09 10 11 12
2014 : 01 02 03 04 05 06 07 08 09 10 11 12
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12

サイト

Vim入門

C言語入門

C++入門

JavaScript/Node.js入門

Python入門

FreeBSD入門

Ubuntu入門

セキュリティ入門

パソコン自作入門

ブログ

トップ


プライバシーポリシー