Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【Java】Jacksonがパースする文字列のフィールド名にDouble Quoteがついていない状態でもパース可能にする

Jackson

github.com

Double-Quote問題

JacksonのObjectMapperでJSON文字列パースしてJavaオブジェクトに変換するとき、フィールド名にダブルクォートがないと怒られてしまいます。

String json = "{user_id: 1, age: 20, item_id: 2, item_name: "hoge"}";
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, String>> type = new TypeReference<Map<String, String>>() {}
List<Map<String, String>> list = mapper.readValue(json, type);
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('u' (code 105)): was expecting double-quote to start field name
 at [Source: {user_id: 1, age: 20, item_id: 2, item_name: "hoge"}; line: 1, column: 4]

そのため、クォートなしのJSONをパースするためには mapper.configure()メソッドでFeature.ALLOW_UNQUOTED_FIELD_NAMESフラグを有効化します。

mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

参考

github.com

【Java】Jacksonで配列形式のJSON文字列をJavaオブジェクトに変換する

Jackson

rennnosukesann.hatenablog.com

配列形式のJSON

JSONのrootがオブジェクト形式ではなく配列形式の場合、ObjectMapperによるパースは以前の記事同様TypeReferenceを用いて行うことができます。

rennnosukesann.hatenablog.com

rootが配列形式のJSON
[
    {
        "user_id": 1,
        "age": 20
    },
    {
        "user_id": 2,
        "age": 22
    },
]
Usage
String json = "[{ "user_id": 1, "age": 20}, {"user_id": 2, "age": 22}]";
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<Map<String, String>>> type = new TypeReference<List<Map<String, String>>>() {}
List<Map<String, String>> list = mapper.readValue(json, type);

参考

github.com

【Shell】expectでシェルの対話的処理を自動化する

expect

expectは、シェル上での対話的なコマンドライン処理を自動化するためのツールです。

シェルスクリプトでルーチンを自動化したいときに対話的な処理が入ってしまって、どうしても手入力が発生してしまう・・・そんなときに重宝します。

Usage

実行環境はMac OS X High Sierra 10.13.4です。

brewGUIツールキットtcl-tkと、expectをインストールします。

$ brew install tcl-tk --without-tcllib
$ brew install expect --with-brewed-tk

tcl-tkのインストールは少し時間がかかります。

Source

以下にscpコマンドでのパスワード入力を自動化するスクリプト例を示します。

#!/bin/bash

TARGET="{target_path}"
PASSWORD="P@ssw0rd"

echo "copy .txt file in '${TARGET}' to remote server ..."

expect -c "
spawn scp ${TARGET}/*.txt usr01@10.132.235.71:~
expect \"usr01@10.132.235.71's password:\"
send \"${PASSWORD}\n\"
interact
"

expect -c

自動化対象となるコマンドリストを引数にとり、引数のコマンドを実行します。

spawn

expectの引数に渡されたコマンドリスト内で使用します。
対話処理を行うコマンドを引数にして渡すことで、後述するsendコマンドによる自動嘔吐が可能な状態になります。

send

spawnコマンドによって実行されたコマンドの対話処理に対して、どのような応答を行うかを定義します。

interact

自動応答処理を終了します。

参考

dot-blog.jp

【NW】PPPoE

PPPoEとは

PPPoEとは、イーサネットを利用してPPPの機能を提供するプロトコルです。

イーサネットはデータリンクとして広く普及した規格です。多くのネットワーク機器やNICがこのイーサネットに準拠しています。

rennnosukesann.hatenablog.com

rennnosukesann.hatenablog.com

しかし、イーサネットがサポートする機能だけでは限界があります。例えば、イーサネットにはコネクションの確立・切断機能はありません。また二点間の認証機能も持ち合わせておりません。

そのような機能に対するニーズをイーサネットで満たすため、インタフェースとしてはイーサネットでありながら、PPPの機能を提供する新しい形のプロトコルが生まれました。それがPPPoEです。

利用用途として、一般家庭とプロバイダ間のデータリンク接続が挙げられます。プロバイダとしてはデータ通信の利用者の識別や利用時間等の計測を行いたいので、コネクションの確立や認証を必要とします。PPPoEであれば、これらをイーサネットの形で行うことができるので、多くのプロバイダが顧客とのデータリンクの接続にPPPoEを採用しています。

※PPPについてはこちらの記事参照 rennnosukesann.hatenablog.com

PPPoEのステージ

PPPにおける通信では、すでに送信先の相手との通信経路が固定された状態で通信が行われます。一方で、イーサネットではブロードキャスト通信などにより多数の送信先に対して無指向通信を行い、データの送信先ホストだけが返信を行うという形でデータの送受信を行います。そのため、イーサネット上でPPPとして振る舞うPPPoEは、このイーサネットの無指向通信の上でPPPの通信を再現する必要があります。

PPPの通信を再現するため、PPPoEでは通信処理を以下の二段階に分けて定義しています。

  • ディスカバリステージ
  • PPPセッションステージ

ディスカバリステージ

ディスカバリステージでは、送信先相手へのMACアドレスの伝達を行います。また、後述するPPPセッションステージで用いるセッションIDの特定・セッションの確立も行います。

PPPセッションステージ

ディスカバリステージによってセッションが確立されて以降は、PPPに則った通信が開始されます。

PPPoEのフレームフォーマット

f:id:rennnosukesann:20180722163810p:plain

イーサネットヘッダ

イーサネットで規定されているヘッダです。詳しくはこちら

PPPoEヘッダ

PPPoEで必要な情報を含むヘッダ。

PPPプロトコル

PPP上で用いられるプロトコル

FCS

フレームの破損を検出するためのシーケンス番号。

参考

(マスタリングTCP/IP 入門編 第5版)[https://www.amazon.co.jp/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0TCP-IP-%E5%85%A5%E9%96%80%E7%B7%A8-%E7%AC%AC5%E7%89%88-%E7%AB%B9%E4%B8%8B/dp/4274068765)

milestone-of-se.nesuke.com

PPPoE - Wikipedia

【NW】PPP

まえがき

この記事は、4年前に投稿したPPPに関する記事のリライトになります。

rennnosukesann.hatenablog.com

結構前に書いたもので内容うろ覚えだったので、復習も兼ねて再度調査してまとめ直してみました。

上記記事にない情報も追加したので、双方参照していただけると嬉しいです。

PPPとは

PPP(Point to Point Protocol)とはデータリンク層プロトコルであり、一対一でコンピュータを接続するためのデータリンク仕様を定義しています。

前回の記事で紹介したイーサネットは、物理層データリンク層にまたがる規格でした。PPPは物理層に該当する仕様はなく、純粋なOSI第二層データリンクプロトコルになります。

rennnosukesann.hatenablog.com

rennnosukesann.hatenablog.com

そのため、PPPをデータリンク層プロトコルとして採用した場合、物理層に該当する規格・プロトコルを別途選定する必要があります。その点で、PPPはイーサネットと比較して物理レベルでは柔軟と言えます。

LCP/NCP

PPPはLCP(Link Controll Protocol)とNCP(Network Controll Protocol)の2つのプロトコルに分類することができます。LCPは上位層のプロトコルに依存しないプロトコルであり、逆にNCPは上位層に依存するプロトコルになります。

PPPではデータ通信開始時、PPPレベルでのコネクションの確立を行います。コネクション確立時には認証、圧縮、暗号化の設定も行います。LCPはそれらの処理について責務を持ち、コネクションの確立・切断、プロトコルの設定、通信品質監視設定等を行います。

NCPは上位層のプロトコルに依存するため、ネットワーク層プロトコルによって定義が変わります。

PPPの認証方式

PPPでは、エンドポイント間のコネクション確立時に認証を行います。このとき、LCPの中で複数の認証方式から一つを採用します。PPPで利用される認証方式には、PAP(Password Authentication Protocol)とCHAP(Challenge Handshake Authentication Protocol)の二種類があります。

PAP(Password Authentication Protocol)

PAPはその名の通り、パスワードによる認証を行います。パスワードとIDを相手に送信することで認証を行うのですが、これらのデータは平文で送信されてしまいます。

CHAP(Challenge Handshake Authentication Protocol)

こちらはチャレンジレスポンス方式を利用した認証方式を採用します。

チャレンジと呼ばれる意味のないビット列から特定の関数を用いて新たな値Aを計算し、それを相手に送ります。相手は送信元と同じ関数を持っているので、もとのビット列から同じ計算を行い値Bを生成します。相手はAとBを比較し、一致していることが確認できたら認証を完了します。

チャレンジレスポンスでは毎回渡すビット列を変更しているので、PPPと比較して一回の認証に対する盗聴に強いという特徴を持ちます。ただし、共有する関数を第三者に知られていないということが前提になります。

PPPデータフレームフォーマット

PPPのデータフレームフォーマットは以下の様になっています。

f:id:rennnosukesann:20180722152907p:plain

フラグ

フレームの先頭・末尾に付加される、通信の開始・終了を表すビット列です。

アドレス

送信先アドレスを指します。基本的に、この領域には11111111(ブロードキャスト)が挿入されます。

制御

データリンクプロトコルHDLCで規定される「非番号制フレーム」を表す制御ビット00000011が挿入されます(PPPはHDLCを参考に作られている)。

データ

上位層プロトコルによるデータ・コンテンツを含む領域。

タイプ

データ部の上位プロトコルタイプが挿入されます。

FCS

フレームの破損検出を行うためのビット列です。

参考

(マスタリングTCP/IP 入門編 第5版)[https://www.amazon.co.jp/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0TCP-IP-%E5%85%A5%E9%96%80%E7%B7%A8-%E7%AC%AC5%E7%89%88-%E7%AB%B9%E4%B8%8B/dp/4274068765)

tech.nikkeibp.co.jp

milestone-of-se.nesuke.com

【NW】無線LAN規格IEEE802.11

IEEE802.11

IEEE802.11は、IEEEが定義した無線LANプロトコルにおける物理層データリンク層(の一部)の規格の総称です(元祖IEEE802.11の規格名でもあります)。

IEEE802.11には規格内容によって無印/a/b/g/nなどの種類があり、それぞれ最大速度や周波などの特徴が異なります。基本的に後者ほど新しい規格となり、通信速度も向上しています。

近年無線通信の通信向上とともに、オフィスや一般家庭、店舗などでも利用されるようになり、ネットワーク技術の中でも特に注目を浴びている規格です。

CSMA/CA

IEEE802.11では、通信品質を向上するために CSMA/CA(Carrier Sense Multiple Access with Collision Avoidance)と呼ばれるアクセス制御方式を用いています。CSMA/CDは、無線LAN上で他の通信が行われていた場合に、自身の通信と衝突しないよう通信タイミングを調節するアクセス制御を行います。

  1. 通信開始前に、無線上の受信を試みます。他のホストが通信しているかどうかを確認します。

  2. 他のホストが通信をしていなければ、自身の通信を開始します。

  3. 他のホストが通信をしているのであれば、ランダムな時間待機し、待機後再び1.を試みます(永遠に待ち続けるのを防ぐため、待ち時間は徐々に短くなっていきます)。

似たようなアクセス制御にCSMA/CDという方式がありますが、こちらはすぐさま通信を開始し、衝突を検知したときに初めて通信を中断し、ランダム時間待機後に再送を行います。CSMA/CDは有線LAN規格など衝突検出可能な環境下で採用されますが、無線LANでは衝突検出が難しいため、衝突検出を必要としないCSMA/CA方式を採用しています。

IEE802.11(無印)

元祖IEEE802.11規格です。
物理層において電波・赤外線を用い、1~2Mbpsの通信速度を実現します。現在では後述するIEE802.11b/g/a/nの通信速度が優れているためあまり使われません。

IEE802.11a

元祖IEEE802.11と比較すると、飛躍的な通信速度(54Mbps)の進歩を遂げた企画です。
周波数帯が5GHzとなっているため、他の家電等による電波干渉の影響が少ないものの、障害物に弱いという特徴があります。

IEEE802.11b

こちらも元祖IEEE802.11と比較すると通信速度は向上していますが、11MbpsとIEEE802.11aには劣ります。 周波数帯が2.4GHzのため、5GHzと比較して他の無線機器・電磁波の影響を受けやすいですが、障害物に強いという特徴があります。

IEEE802.11g

IEEE802.11bの上位互換です。周波数帯は2.4GHzとかわらぬまま、通信速度が54MbpsとIEEE802.11aと同等になっています。多くの無線LANルーターではIEEE802.11aとgのどちらかが選択できるようになっています。

IEEE802.11n

IEEE802.11gとaの技術をベースにして、アンテナの本数を増やし各通信処理を同期させる技術を採用しています。これをMIMO(Multi-Input Multi-Output)といいます。周波数帯は5GHz帯、2.4GHz帯のどちらかを選べます。他の周波数帯を利用するシステムがない場合には、40GHz帯を利用しての最大150Mbps通信を利用できます。

IEEE802.11ng

IEEE802.11nをさらにグレードアップさせた規格です。帯域幅を最大160GHzにまで拡大できるようになり、理想値で最大速度6.93Gbpsを叩き出します。ただし現在利用できる周波数帯が5GHzのみとなります。

参照

https://ja.wikipedia.org/wiki/CSMA/CA

buffalo.jp

【python】Flaskを使ってAPIサーバを公開する

Flaskとは

Flaskとは、pythonのWebフレームワークです。 軽量なWebフレームワークであり、小さく使い始めることができるのが特徴です。 公式でも"microframework"と銘打っています。

Welcome | Flask (A Python Microframework)

同じpythonフレームワークとしてはDjangoやも挙げられますが、Djangoフルスタックなフレームワークなので、規模が大きめのWebアプリケーション作成に向いている気がします。

Usage

例によってpipでインストールできます。

$ pip install Flask

Anacondaで管理したい人はcondaでも良いでしょう。

$ conda install -c anaconda flask 

Source & Demo

Hello, World!

まずは Hello World から!

# hello.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

サーバを立ち上げてみましょう。

$ FLASK_APP=hello.py flask run

ローカルサーバーが立ち上がるので、ブラウザで開くとHello, Worldが表示されるのがわかります。

f:id:rennnosukesann:20180721150306p:plain

またアプリの実行はスクリプト上でも行うことができます。

# hello.py
from flask import Flask
app = Flask(__name__)
app.run(host="127.0.0.1", port=5000)
$ python hello.py

APIの定義

次はAPIを提供してみましょう。
FlaskではAPIの定義も簡単に行なえます。

from flask import Flask, request, jsonify, make_response
app = Flask(__name__)

@app.route("/hoge", methods=['GET'])
def getHoge():
    # URLパラメータ
    params = request.args
    response = {}
    if 'param' in params:
        response.setdefault('res', 'param is : ' + params.get('param'))
    return make_response(jsonify(response))

@app.route("/hoge", methods=['POST'])
def postHoge():
    # ボディ(application/json)パラメータ
    params = request.json
    response = {}
    if 'param' in params:
        response.setdefault('res', 'param is : ' + params.get('param'))
    return make_response(jsonify(response))

app.run(host="127.0.0.1", port=5000)

@app.routeデコレータの引数にパス・メソッド種別を指定しています。
Hello Worldのときはtext/plainを返していましたが、今回はapplication/jsonJSON形式)でレスポンスを返しています。レスポンスをJSONにするには、jsonify関数を使って作成したJSON型データをmake_response関数の引数に渡し、それをAPI関数の返り値とします。

make_responseはレスポンスヘッダ及びレスポンスボディの情報を持つオブジェクトを作成します。このオブジェクトを介して、リクエストヘッダやボディの編集を行うことができます。

body = { "param" : "hoge"}
response = make_response(jsonify(body))
response.headers['X-HogeHoge'] = 'hoge...' # 新しいヘッダ属性を追加

指定したパスに対してリクエストを投げると、結果が確認できます。

http://127.0.0.1:5000/hoge?param=helloAPI(GET)
Response

f:id:rennnosukesann:20180721155155p:plain

http://127.0.0.1:5000/hoge(POST)
Body

f:id:rennnosukesann:20180721155310p:plain

Response

f:id:rennnosukesann:20180721155317p:plain

参照

http://flask.pocoo.org/