LoginSignup
12
9

More than 5 years have passed since last update.

Goでipcalcを書いた

Last updated at Posted at 2014-06-11

Go歴1日で突撃した #gocon でGo欲を触発され、とにかく何でもいいからGoで書きたくなり、Go版ipcalcを書いてみた

概要

  • https://github.com/goldeneggg/ipcl
  • CIDR形式(例:192.168.1.0/24)の文字列から、取り得るホスト数やIPアドレスのレンジ等を算出・出力する
  • 現状公開されてる計算ツールだと「CIDRを一覧で記載したファイルを入力して一括parse」が可能なものが見当たらなかったので対応した

Go本体のテストコードに助けられた

  • 今回Goを書いてみて最初に浮かぶ感想はこれ。「この処理って標準パッケージ使ってどう書けばいいんだろ?」と迷った時、公式ドキュメントももちろんだが Go本体のテストコードを読むのが良い 。テストの書き方も学べて一石二鳥(Goに限った話じゃ無いかもしれないけど他言語のテストコード読んだこと無いので比較は出来ない。さーせん )
    • Goにはアサーションが無いので、テストの成否は「テスト対象関数/メソッドの戻り値 の内の1つ であるerrorオブジェクト 」で判定するスタイル。当然本体のテストコードも然り
    • そしてこの本体テストコードの「エラーハンドリング→エラー有無での後続処理の切り替え」あたりの書き方が自実装コードに適用出来る場面が割りとあった
      • 今回の用途で言えばnetパッケージの ip_test.go のコードにだいぶ助けられた
  • Goのソースコード(テストコードも含む)は、 Mercurialでローカルに落とす、もしくはここでオンラインで読める
    • hoge.goのテストはhoge_test.goという名前にするのがGo流

備忘

net パッケージ

  • 今回一番お世話になったGo標準パッケージで、TCP/IP, UDP, ソケット、ネットワークI/Oに関連する機能は一通り網羅されている

IP型

  • IP型は、ひとつのIPアドレスを表す型で、実体は[]byte型、16byteのバイト配列
  • CIDRのパースは func ParseCIDR(s string) (IP, *IPNet, error)を使えば一発でやってくれる
    • 戻り値のIPがネットワークアドレスになっている
  • func IPv4(a, b, c, d byte) IPは、IPアドレスの各オクテットの値をbyteで渡してIP型で返す関数。
    • 戻り値のIPは4byteではなく16byteで返ってくるが、これは公式ドキュメントを読む限りIPv6もフォローする為に汎用性を持たせたものと思われる
    • 例えば172.168.1.0のIP型表現は内部的に[]byte型でこうなってる → [0][0][0][0][0][0][0][0][0][0][0][0][172][168][1][0]
    • 4byteで欲しい場合は、 func (ip IP) To4() IP メソッドで変換する

IPNet型

  • 「CIDRで表現されるIPネットワークそのもの」を表すオブジェクト
    • 実体は「ネットワークアドレスを表現するIP型」「ネットマスクを表す`IPMask型」の2つのフィールドを持つstructになっている
  • func (n *IPNet) Contains(ip IP) boolで、指定したIP(IPアドレス)がそのネットワーク範囲内のものか?を判定する事が出来る

IPMask型

  • ネットマスクを表す型で、同じく実体は[]byte
  • プレフィックス長からIPMask型のオブジェクトを取得したい場合はfunc CIDRMask(ones, bits int) IPMaskを使う。bitsにはIPv4なら32を指定

for文

  • 初期値や事後処理で複数パラメータを取るfor文は for i, f, t := 0, 0, 8; i < 4; i, f, t = i+1, f+8, t+8 { ... } って具合に、変数宣言時同様に代入演算子は1つに集約して書く

数値を2進, 16進で表記したい

  • fmt.Sprintf()を使う
  • %b 2進, 前ゼロ埋め8桁で表記したければ%08bする
    • fmt.Sprintf("%08b", 3) // = "00000011"
  • %x 16進, 前ゼロ埋め2桁で表記したければ%02xとする
    • fmt.Sprintf("%02x", 15) // = "0f"
12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9