技術メモ

神奈川在住のITエンジニアの備忘録。おもにプログラミングやネットワーク技術について、学んだことを自分の中で整理するためにゆるゆると書いています。ちゃんと検証できていない部分もあるのでご参考程度となりますが、誰かのお役に立てれば幸いです。

Javaの各数値型の最大値・最小値

Javaの各数値型の最大値・最小値で一目で確認できるようにしたかったので、以下のプログラムを作成した。

public class ShowMaxMin {
    public static void main(String[] args) {
        System.out.println("Byte Min: " + Byte.MIN_VALUE);
        System.out.println("Byte Max: " + Byte.MAX_VALUE);
        System.out.println("Short Min: " + Short.MIN_VALUE);
        System.out.println("Short Max: " + Short.MAX_VALUE);
        System.out.println("Integer Min: " + Integer.MIN_VALUE);
        System.out.println("Integer Max: " + Integer.MAX_VALUE);
        System.out.println("Long Min: " + Long.MIN_VALUE);
        System.out.println("Long Max: " + Long.MAX_VALUE);
        System.out.println("Float Min: " + Float.MIN_VALUE);
        System.out.println("Float Max: " + Float.MAX_VALUE);
        System.out.println("Double Min: " + Double.MIN_VALUE);
        System.out.println("Double Max: " + Double.MAX_VALUE);
    }
}


実行結果は以下の通り。

Byte Min: -128
Byte Max: 127
Short Min: -32768
Short Max: 32767
Integer Min: -2147483648
Integer Max: 2147483647
Long Min: -9223372036854775808
Long Max: 9223372036854775807
Float Min: 1.4E-45
Float Max: 3.4028235E38
Double Min: 4.9E-324
Double Max: 1.7976931348623157E308

あと、JavaにはBigInteger型とBigDecimal型がある。これらについて調べてみたところ、明示的な最大値・最小値は存在せず、どこまでの数値を表現できるかは、その環境のスペックに依存するようだ。この辺りについてはあまり理解できていないので、今後の追加調査項目としておく。

SNMP getbulk の nonRepeaters オプション

以前、以下の記事を書いた時に、
akrad.hatenablog.com
SNMPのgetbulkで出てくる nonRepeaters が何なのかあまり分かっていなかったので、今回それを調べてみた。

まず、nonRepeaters については、
http://net-snmp.sourceforge.net/wiki/index.php/GETBULK
に以下の記載がある。
「the number of objects that are only expected to return a single GETNEXT instance, not multiple instances. Managers frequently request the value of sysUpTime and only want that instance plus a list of other objects.」

ざっくり言うと、nonRepeaters は、getbulkで取得対象とした OID の中で繰り返し取得を行わないものの個数であると思われる。例えば、getbulk で OID1, OID2, OID3 配下のMIBを getbulk で取得するとして、nonRepeaters を 2 とすると、OID1 と OID2 については繰り返し取得を実施せず、OID3 についてだけは繰り返し取得を実施する。

以下、上記の解釈で正しいのか、サンプルプログラムを作って調査した。

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Snmpbulk {
    public static void main(String[] args) {
        // Set value for snmp getbulk
        String targetAddr = "localhost";
        String oidStr1 = ".1.3.6.1.2.1.1";
        String oidStr2 = ".1.3.6.1.2.1.2";
        String oidStr3 = ".1.3.6.1.2.1.3";
        String commStr = "public";
        int snmpVersion = SnmpConstants.version2c;
        String portNum = "161";
        int timeout = 3000;
        int retryCnt = 1;
        int maxRepetitions = 5;

        // Create target
        CommunityTarget target = new CommunityTarget();
        target.setAddress(new UdpAddress(targetAddr + "/" + portNum));
        target.setCommunity(new OctetString(commStr));
        target.setTimeout(timeout);
        target.setRetries(retryCnt);
        target.setVersion(snmpVersion);

        // Create pdu
        PDU pdu = new PDU();
        pdu.setType(PDU.GETBULK);
        pdu.setMaxRepetitions(maxRepetitions);
        pdu.setNonRepeaters(2); // ★NonRepeatersには 2 をセット。
        OID targetOID1 = new OID(oidStr1);
        OID targetOID2 = new OID(oidStr2);
        OID targetOID3 = new OID(oidStr3);
        pdu.add(new VariableBinding(targetOID1));
        pdu.add(new VariableBinding(targetOID2));
        pdu.add(new VariableBinding(targetOID3));


        Snmp snmp = null;
        try {
            snmp = new Snmp(new DefaultUdpTransportMapping());
            snmp.listen();
            // Execute snmp GetBulk
            ResponseEvent responseEv = snmp.getBulk(pdu, target);

            // Get response
            PDU response = responseEv.getResponse();

            // ---------------------------------
            // Analyze response
            // ---------------------------------
            if (response == null) {
                System.out.println("Request timeout...");
                return;
            }
            if (response.getErrorStatus() != SnmpConstants.SNMP_ERROR_SUCCESS) {
                System.out.println("Error happened...");
                System.out.println(response.getErrorStatusText());
                return;
            }
            int numVarBinds = response.size();
            for (int i = 0; i < numVarBinds; i++) {
               VariableBinding varbind = response.get(i);
               if (varbind == null) {
                   continue;
               }
               if (varbind.isException()) {
                   System.out.println(varbind.getOid() + " : " + "Exception happened");
                   continue;
               }
               System.out.println(
                   varbind.getOid() +
                       " : " +
                   varbind.getVariable().getSyntaxString() +
                       " : " +
                   varbind.getVariable());
            } // for
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (snmp != null) {
                    snmp.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

上記の通り、snmp4j ライブラリを使って getBulk を実行している。snmp4j は有名なライブラリで RFC に沿っているはずなので、それで実装して実機検証すれば、事実が分かるというスタンスである。
上記のプログラムの実行結果は以下である。

1.3.6.1.2.1.1.1.0 : OCTET STRING : xxxxx
1.3.6.1.2.1.2.1.0 : Integer32 : 42
1.3.6.1.2.1.4.1.0 : Integer32 : 2
1.3.6.1.2.1.4.2.0 : Integer32 : 128
1.3.6.1.2.1.4.3.0 : Counter : 2509066
1.3.6.1.2.1.4.4.0 : Counter : 0
1.3.6.1.2.1.4.5.0 : Counter : 6

想定通り、「.1.3.6.1.2.1.1」と「.1.3.6.1.2.1.2」については繰り返し取得が実施されておらず、「.1.3.6.1.2.1.3」に対してのみ繰り返し取得が実施されている。なお、検証で用いたSNMPエージェントは「.1.3.6.1.2.1.3」のMIBを持っていないので、「.1.3.6.1.2.1.3」への取得要求に対して、SNMPエージェントは「.1.3.6.1.2.1.4」配下のMIBを返している。

これにより、nonRepeaters については冒頭に述べた理解で合っていると思う。

内部通信をパケットキャプチャする方法

Linuxでは、OS標準の tcpdump コマンドで内部通信のパケットキャプチャを取得することができる。tcpdump コマンドのオプションで「-i lo」を付ければ良い。

ちなみに、tcpdump コマンドで「-w dumpfile.cap」を指定すると、dumpfile.cap に、 wireshark 上で表示可能な形式でパケットダンプが出力される。

 

一方、Windowsでは、OS標準の機能では内部通信のパケットキャプチャを取得することはできない(はず)。それを実現したい場合、RawCap等のツールを導入するか、内部通信でも一度外部に通信が出るように (パケットキャプチャが張っているレイヤを通るように)、OSのルーティング・テーブルを弄る、といった手段がある。

 

パケットキャプチャというと、外部との通信の情報を取得するイメージを持つ人が多いと思うのが、OS内のプロセス間通信(内部通信)の情報を取得したくなることもあるので、ここに書いておく。

JavaでSNMP GetBulk

JavaSNMP Get Bulk を実行するコードを作ってみた。とりあえずざっと作ってみただけなので、SNMP要求を出すターゲットの情報などはソース中にハードコードしている。
実行すると、localhost上のSNMPエージェントに対して、.1.3.6.1.2.1.1 から数えて20個のMIBを取得する。.1.3.6.1.2.1.1 (system MIB)配下は通常20個もMIBは無いので、.1.3.6.1.2.1.1 配下のMIBを取得し終わると、.1.3.6.1.2.1.2 以降のMIBも取得する。なお、snmp4j が提供するAPIを使用しているため、コンパイル、実行するには snmp4j が必要。

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class Snmpbulk {
    public static void main(String[] args) {
        // Set value for snmp getbulk
        String targetAddr = "localhost";
        String oidStr = ".1.3.6.1.2.1.1";
        String commStr = "public";
        int snmpVersion = SnmpConstants.version2c;
        String portNum = "161";
        int timeout = 3000;
        int retryCnt = 1;
        int maxRepetitions = 20;

        // Create target
        CommunityTarget target = new CommunityTarget();
        target.setAddress(new UdpAddress(targetAddr + "/" + portNum));
        target.setCommunity(new OctetString(commStr));
        target.setTimeout(timeout);
        target.setRetries(retryCnt);
        target.setVersion(snmpVersion);

        // Create pdu
        PDU pdu = new PDU();
        pdu.setType(PDU.GETBULK);
        pdu.setMaxRepetitions(maxRepetitions);
        pdu.setNonRepeaters(0);
        OID targetOID = new OID(oidStr);
        pdu.add(new VariableBinding(targetOID));

        Snmp snmp = null;
        try {
            snmp = new Snmp(new DefaultUdpTransportMapping());
            snmp.listen();
            // Execute snmp GetBulk
            ResponseEvent responseEv = snmp.getBulk(pdu, target);

            // Get response
            PDU response = responseEv.getResponse();

            // ---------------------------------
            // Analyze response
            // ---------------------------------
            if (response == null) {
                System.out.println("Request timeout...");
                return;
            }
            if (response.getErrorStatus() != SnmpConstants.SNMP_ERROR_SUCCESS) {
                System.out.println("Error happened...");
                System.out.println(response.getErrorStatusText());
                return;
            }
            int numVarBinds = response.size();
            for (int i = 0; i < numVarBinds; i++) {
               VariableBinding varbind = response.get(i);
               if (varbind == null) {
                   continue;
               }
               if (varbind.isException()) {
                   System.out.println(varbind.getOid() + " : " + "Exception happened");
                   continue;
               }
               System.out.println(
                   varbind.getOid() +
                       " : " +
                   varbind.getVariable().getSyntaxString() +
                       " : " +
                   varbind.getVariable());
            } // for
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (snmp != null) {
                    snmp.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


実行すると、Getbulkで取得したMIB値が以下のように表示される。

1.3.6.1.2.1.1.1.0 : OCTET STRING : xxxx
1.3.6.1.2.1.1.2.0 : OBJECT IDENTIFIER : 1.3.6.1.4.1.311.1.1.3.1.1
1.3.6.1.2.1.1.3.0 : TimeTicks : 2 days, 22:32:36.34
1.3.6.1.2.1.1.4.0 : OCTET STRING :
1.3.6.1.2.1.1.5.0 : OCTET STRING : xxxx
1.3.6.1.2.1.1.6.0 : OCTET STRING :
1.3.6.1.2.1.1.7.0 : Integer32 : 76
1.3.6.1.2.1.2.1.0 : Integer32 : 42
1.3.6.1.2.1.2.2.1.1.1 : Integer32 : 1
1.3.6.1.2.1.2.2.1.1.2 : Integer32 : 2
1.3.6.1.2.1.2.2.1.1.3 : Integer32 : 3
1.3.6.1.2.1.2.2.1.1.4 : Integer32 : 4
1.3.6.1.2.1.2.2.1.1.5 : Integer32 : 5
1.3.6.1.2.1.2.2.1.1.6 : Integer32 : 6
1.3.6.1.2.1.2.2.1.1.7 : Integer32 : 7
1.3.6.1.2.1.2.2.1.1.8 : Integer32 : 8
1.3.6.1.2.1.2.2.1.1.9 : Integer32 : 9
1.3.6.1.2.1.2.2.1.1.10 : Integer32 : 10
1.3.6.1.2.1.2.2.1.1.11 : Integer32 : 11
1.3.6.1.2.1.2.2.1.1.12 : Integer32 : 12

そういえば、nonRepeaters が何なのかイマイチ分かっていない。。後日調査してブログに書くことにする。

Active Directoryで出てくる用語 (DN, OU, DC, CN など)

Active Directory の環境構築を行っていると、DN, OU, DC, CN など、何のことかよく分からない用語が出てくる。ここでは、それらについて簡単に纏める。

 

これらは rfc2253 に記載がある。

https://www.ietf.org/rfc/rfc2253.txt

抜粋すると以下の通り。

String X.500 AttributeType
------------------------------
CN           commonName
L               localityName
ST            stateOrProvinceName
O              organizationName
OU           organizationalUnitName
C              countryName
STREET   streetAddress
DC            domainComponent
UID           userid

DN (Distinguished Name) は、上記を組み合わせて実現される、Active Directory 内におけるオブジェクトの一意表現である。例えば、以下のような感じ。

CN=taro, OU=development, DC=xxxxxcompany, DC=co,DC=jp

この辺の説明については、以下のページが分かりやすい。

Active Directoryオブジェクトの識別名(DN)とは:Tech TIPS - @IT

MessageListenerクラスのonMessageメソッド

JavaのJMS(Java Message Service)の受信側でコールされるMessageListener#onMessage()は、並列して走ることがあるのか調べてみた。

まず、JavaDocを読んでみる。

・・・the onMessage method is not called with the next message until the session has completed the last call.

MessageListener (Java(TM) EE 7 Specification APIs)

これによると、並列して走らないように読める。以下のページにも並列して走らないという記載がある。

MessageListener#onMessage() is executed as part of session thread, so you will not receive next message until return from onMessage().

java - JMS: Can we get multiple messages from queue in OnMessage() withtout commit or rollback - Stack Overflow

 

JMSの仕様として、MessageListener#onMessage()はシーケンシャルになるので、この処理の中では排他は考えなくても大丈夫だと思われる。

MIBファイル内の定義における大文字・小文字の使い分け

SNMPで使用されるMIBファイルでは、以下のように大文字・小文字が使い分けられていることが多い。RFCでの定義例はそうなっている。 

・・・

evalEntry OBJECT-TYPE    ★オブジェクト定義は先頭が小文字
    SYNTAX EvalEntry          ★シンタックス定義は先頭が大文字
    MAX-ACCESS not-accessible
    STATUS current
    DESCRIPTION
          "An entry (conceptual row) in the evaluation table."
    INDEX { evalIndex }
    ::= { evalTable 1 }

EvalEntry ::=    ★シンタックス定義は先頭が大文字
    SEQUENCE {
        evalIndex Integer32,
        evalString DisplayString,
        evalValue Integer32,
        evalStatus RowStatus
  } 

・・・

RFC 2578 - Structure of Management Information Version 2 (SMIv2)

 

上述の通り、オブジェクト定義では先頭が小文字になっていて、シンタックス定義では先頭が大文字になるのが慣例のようだが、これについて明文化しているドキュメントは見つけられなかった。SMIv2 は ASN.1 のサブセットなので、ASN.1 のドキュメントを漁れば何か情報が見つかるかもしれないが、そこまでは見れていない。。

大文字・小文字を分けないと、解析失敗するMIBパーサもあるかもしれないので、MIBファイルを作成する際には、慣例に従って、大文字・小文字を分けた方が良いと思われる。