Entry

プログラミングメモ - IP の文字列を long 値に変換

2009年03月29日

おとなしく inet_aton(3) を使えよって噂もあるんだけれども,ふとやってみたくなったので書いてみた。ネットのあちこちで書いてる方がいらっしゃるので,あまり意味ないです。

#include <iostream>
#include <stdexcept>
#include <string>

unsigned long
getAddressLong(const std::string& addr) throw (std::runtime_error) {
  unsigned long ret = 0;
  unsigned long fieldNumber = 0;
  int fieldCount = 0;
  std::string::const_iterator itr;
  
  for (itr = addr.begin(); ; itr++) {
    if (*itr >= '0' && *itr <= '9') {
      fieldNumber *= 10;
      fieldNumber += *itr - '0';
      if (fieldNumber > 255) {
        throw std::runtime_error("field range error.");
      }
    } else if (*itr == '.' || itr == addr.end()) {
      fieldCount++;
      if (fieldCount > 4) {
        throw std::runtime_error("field count error.");
      }
      ret <<= 8;
      ret += fieldNumber;
      fieldNumber = 0;
      if (itr == addr.end()) {
        break;
      }
    } else {
      throw std::runtime_error("invalid character in IP string.");
    }
  }
  if (fieldCount != 4) {
    throw std::runtime_error("field count error.");
  }
  return ret;
}

int
main(int argc, char* argv[]) {
  try {
    std::cout << getAddressLong("192.168.0.1") << std::endl;
    std::cout << getAddressLong("0.0.0.0") << std::endl;
    std::cout << getAddressLong("255.255.255.255") << std::endl;
//  std::cout << getAddressLong("256.256.256.256") << std::endl;
//  std::cout << getAddressLong("-1.0.4.12") << std::endl;
//  std::cout << getAddressLong("168.0.1") << std::endl;
  } catch (std::runtime_error& e) {
    std::cerr << e.what() << std::endl;
  } catch (...) {
    std::cerr << "unknown error." << std::endl;
  }
  return (0);
}

a.b.c.d 形式の IP アドレスを unsignd long にして返します。inet_aton(3) の man を見ると,POSIX では a.b.c 形式や a.b 形式の IP アドレスも読めなきゃいけないみたい。こゆ表記もあったんだ。

答え合わせがてら,OpenBSD の実装を見たところ,当然のことがら上記の形式にも対応していました。つか,16進や8進表記にも対応してるんだ。知らんかった。そういえば,エンディアンについても気にしてないなぁ。

こりゃ自分で作るより素直に inet_aton(3) を使った方がよさげ。Windows の場合は WinSock の inet_addr() を使うことになるのかな。

IP の文字列を long にできると,例えば DB のユニークなキーにするのに都合が良かったりします。IPv4 なら,4 bytes 固定でユニークな値を得ることができるから,単純に容量を節約できる。数値なので検索も速い。URL との対応は取れないけど,アクセスログやセッション管理のようなとこでは時々使われているみたいです。

今,C++ で CGI フレームワーク(書くたびに呼び名が変わってるな)を作ってるんですけど,セッションモジュールをどうにかしようかと思ってちと書いてみたのでした。結論は,「API を使え」ということになりそ。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN