シェルスクリプトマガジン

test

バーティカル・マイスターの修行時代 その1

投稿日:2017.05.30 | カテゴリー: 記事

written by シェルスクリプトマガジン編集部

この記事は、シェルマガvol.48掲載「バーティカルバーの極意」第二回の、いわゆる「やってみた記事」です。
シェルマガ本誌と一緒にご覧頂けると、よりお楽しみいただけます。

はじめに

よちよち歩きで運用を開始した、Web版シェルスクリプトマガジン shell-mag.com 。

更新のたびにFacebookやTwitterなどのSNSに投稿をしてお知らせしていますが、当然お知らせがどれだけの人に届いたか、気になるものです。

たとえばこちらの投稿。

「さて、この投稿のリーチ(投稿が見られた数)は……ええー、たったの70?(しょんぼり)」

たとえばFacebookでは、これまでにリーチが1000近くまで伸びた投稿もあるので、100以下はちょっと堪えます。

まだまだ記事数こそ少ないですが、面白おかしく役に立つ記事を揃えていると自負していますから、せっかく更新した記事が人の目にも触れないと、こちらとしては面白くありません。
なんとかFBでもリーチ数を稼がねば。

Facebookのアルゴリズムではリアクションが多くついた投稿ほど頻繁に表示されるらしいので、リーチを伸ばす正攻法は、まずはキャッチーな、「いいね」をもらいやすい投稿をすることです。
とはいえ、「いいね」をもらえるかどうかはなかなか水物です。なんとか確実にリーチ数を稼ぐ方法はないものか。

そこで、わたくし考えました。

シェルマガの読者さんは皆さま品行方正でしょうから、わたくし編集Kみたいに昼間からSNSに入り浸ったりはせずに、仕事に疲れ、傷つき、リラックスしたい時間だけSNSにアクセスしているはず。
だとすれば、多くの人が休憩をとる、リーチが伸びやすい時間帯があるはずです。

その時間を狙って更新情報を投稿するように心がければ

→自動的にshell-mag.comの利用が増える

→満足した読者さんの口コミでサイトの知名度が上がる

→シェルマガ本誌も売上が伸びる

→編集Kの給料も上がる

と、おお、これはいいことづくめだ!すぐにでも解析をせねば。

……と考えていたところに、前号から始まった、飯尾淳先生による「バーティカルバーの極意」第2回の原稿が届きます。早速確認してみると、おあつらえ向きに「Facebookの投稿をヒストグラムで分析する」内容ではないですか。

「これは使えるぞ!」と、ピーンと来た編集K。
記事のコードチェックも兼ねて、Facebookへの投稿の解析を試みることにしたのでした。

シェルマガvol.48に掲載された「バーティカルバーの極意」第二回では、どの時間帯に飯尾先生がFacebookに投稿しているのか、ヒストグラムで可視化をしていましたが、私の目的である「どの時間帯に投稿すればリーチが伸びるのか」を分析するためには、ヒストグラムよりも散布図のほうが役に立つはずです。

理想的には、例えば下の図のように、「昼休みに入る12時前後と定時の18時前後の投稿は、他の時間帯に比べてリーチ数が伸びやすい」のような傾向が見て取れるはず。

(Excelでちまちまつくりました)

善は急げ。早速Facebookからデータを取得して、解析してみましょう!

苦闘の記録

手元には飯尾先生のお手本があるから、今回の解析は簡単にできるはず……との目論見は、初っ端から崩れます。ビジネスアカウントでは、投稿情報の取得の際に、なんと28日しか遡れないのです。その間の投稿数は10程度。とても、議論ができるサンプル数ではありません。

しょうがないので、投稿日時とリーチ数が表示されるページから、マウスで選択してコピペする原始的な方法でテキストデータを引っ張ってきます。

原始的な方法でデータを取得するの図。ビーッと引っ張ってきます。

さて、取得したデータをテキストにペーストしてみると……

……あれ?

飯尾先生の記事では「データがすべて横に並んでいたので改行コードを挿入して扱いやすいデータにする」というストーリーでしたが、私が取得したデータは、逆にすべて縦に並んでいます。これは困ったなぁ。

困ったときは相談だ。というわけで、隣の席のエンジニアに助け舟を出してもらいます。

編集K「ねぇねぇ、この全部縦に連なったデータを、常識的な並び方に直すにはどうしたらいいかねぇ」
エンジニア「そりゃ、一度全部横にしてから、適当な改行コードを入れるしかないでしょ(編:だよねぇ~)。そういうときはyarrコマンドを使ったらいいんだよ」

yarr(横アレイ)!!ここでまさかのTukubaiコマンド登場です。そりゃまぁ、Tukubaiコマンドを使っていかに楽をしてシステムを組み立てるかを日夜考えている、うちのエンジニアに聞いたら当然そういう答えが返ってきますよね。
注:Tukubaiコマンドは、シェルマガの発行元USP研究所が開発しているUNIXコマンド群。シェルマガ著者の今泉光之さん曰く「便利すぎて考えなくて済むから、エンジニアが馬鹿になる」とのこと個人用Tukubaiのご購入はこちら

オーケーオーケー。他のサイトならまだしも、ここはshell-mag.com 。ユニケージの広報サイトでユニケージのために開発されたコマンドを使って何が悪い。ちょっとズルいですが、Tukubaiコマンドを使っちゃいましょう。
yarrは、縦に並んだデータを横に並び替えるコマンドです。こんなこともあろうかと優しい誰かが作ってくれていたのでしょう。
sedで半角スペースを適当な文字列に変換してから、yarrコマンドでデータの縦横を入れ替えます。

2017年5月31日追記:飯尾先生から「標準的なコマンドだけでも、pasteを使えば同じことができるよ」とご指摘をいただきました。yarrをpasteに置き換え、以下のようにオプションを使えば同じ出力が得られます。

で、こいつをcatで開いてみると……

あれ、縦のまんまだ?どういうことよ。(注:pasteコマンドを使っても結果は同じです)

Vimで開いてみると

おお、紫でハイライトされている^Mの改行コードが残っているんですな。こいつもsedで取ってやりましょう。

ただし、この制御コードの^Mは、素直に「はっと・えむ」とキーを打ってもsedで認識してくれません。キー入力としては、Ctrl-v Ctrl-mと入力すると制御コードの^Mと認識されるので、入力の際には

とタイプしてください。さらっと流しましたが、これを調べるのに20分かかりました。

さて、無事にデータが横一行に並んだので、飯尾先生の教えの通り、sedを使って特定のテキストを改行コードに置き換え、データを扱いやすい形に整えます。今回は、各投稿の最後に「投稿の広告を出す」という一文が必ず入っているので、これを改行コードに書き換えました。

ここもさらっと流していますが、編集Kの使っているMacのOSのバージョンが古かったのか、改行コードを改行コードとして認識してもらえませんでした。再度隣席のエンジニアに頼み、彼のMacで同じコマンドを打ってもらったところ、想定通り改行されましたので、読者の皆さまは安心して記事のコードを使ってください。

さて、こうやって加工したデータですが、まだ行頭に空白があったり、最終行に空行が入っていたりと、まだ形を整える必要があります。AWKとかを使うのがめんどくさいので、再度Tukubaiコマンドを使って加工します。末尾の行を削って、余分な空白をとって、日付と時間とリーチのフィールドを取り出します。

ctail :ファイルの末尾指定行を削って出力

self : 指定したフィールドのデータを取り出す。連続した空白をひとつに削ることができる。

こうやって、弊社のプロダクトを自然にステマしながら加工したデータがこちらになります。

おお、綺麗になった。でもリーチ(第3フィールド)に3桁ごとのカンマが残ってますね。これもsedで消してしまいましょう。ついでにhourとminuteの間のコロンを空白に変えて、それぞれを独立したフィールドにしてしまいます。で、minuteの方を60進法から10進法に直して、hourと合計を出します。

これで、プロットする元データが加工できました。第1フィールドが時刻、第2フィールドがリーチ数です。

さて、元記事に倣って、これをRでグラフにしてみます。

飯尾先生の記事ではhist関数を使っていますが、今回つくるのはヒストグラムではなく散布図なので、plot関数を使います。最初に横軸と縦軸を指定します。$V1、$V2は、それぞれ何フィールド目かを表します。小室哲哉とYOSHIKIが組んだユニットではありませんし、も出てきません。何の話だ。グラフの範囲をxlim、ylimで指定、xlab、ylabでそれぞれ軸のラベルを指定します。

完成!

で、ここまで3時間ほど苦闘した末、完成した散布図がこちらになります。

(縦軸がリーチ数、横軸が投稿時刻になります)

お、おう……。

正直、傾向はよくわかりませんな。当初は12時と18時前後に投稿するとリーチが増えるんじゃないかと考えていましたが、別段そんなこともない。強いて言えば、15時頃はリーチが安定して見えますが、これもサンプル数が少なくて確実とはいえんなぁ……。

とりあえずの結論としては
「投稿の時間帯だけでリーチ数をコントロールしようとするのは無理がある」
ということですね。やはり正攻法で、キャッチーな投稿を心がけねば。

 

というわけで、皆さまもどうぞシェルマガの記事を自分なりに試して楽しんでくださいね!
当サイト掲載のコードもコピペなどにどうぞご利用ください。

今回の記事の元ネタ「バーティカルバーの極意 第二回」のコードはこちら。コピペなどにご利用ください。
解説はシェルマガ本誌をご参照くださいませ。

(次回、「バーティカル・マイスターの遍歴時代」に続く……のか?)

Vol.48

投稿日:2017.05.24 | カテゴリー: バックナンバー

金沢大学・大野先生が、シェルスクリプトを活用した電子工作を伝授する「電子工作塾」。
今回は「回路を設計するより前に」、世界の電気街として名を轟かせる深センにマイ基盤を発注してしまいます。

すずきひろのぶ氏による人気連載「スズラボ通信」では、IFTTTを利用して「ボタンを押せばLINEにメッセージが届くIoTなアレ」をつくる方法を紹介します。

その他にも、業界を代表するスターエンジニア、伊藤直也さんと柄沢聡太郎さんが「エンジニアの生存戦略」を熱く語ったトークライブイベント「TechLION vol.29」の再録記事や、
UMLによる設計記述と導入として、ロバストネス分析とシーケンス図の利用法を紹介した「オレとRubyプログラミング」など、

強くしなやかなITエンジニアを今月も全力で応援するシェルスクリプトマガジン vol.48。
お見逃しなく! !

漢のUNIX ライブラリをつくってみよう! #その5(vol.48掲載)

投稿日:2017.05.23 | カテゴリー: 記事

著者:後藤大地
前回は静的ライブラリを作る方法を取り上げた。.cのファイルを.oのファイルへコンパイルし、それらをまとめて静的ライブラリとする。静的ライブラリはいわば部品の集まりで、コンパイル時にこの静的ライブラリから必要な部品を持ってきて利用することになる。コンパイルごとに静的ライブラリから部品がコピーされ、生成されるバイナリファイルへ含まれることになる。

ライブラリにはもうひとつ「共有ライブラリ」というものがある。動的ライブラリと呼ばれることもある。共有ライブラリの方はバイナリファイル生成時に指定はするものの、ここから部品をコピーしてバイナリに組み込むといったことはしない。生成したバイナリを実行するときにリアルタイムに共有ライブラリを見に行って、そのときに使われる。

記事本文掲載のシェルスクリプトマガジンvol.48は以下リンク先でご購入できます。

 

40歳から始める、オレとRubyプログラミング(vol.48掲載)

投稿日:2017.05.23 | カテゴリー: 未分類,記事

著者:しょっさん

 前回、ページ数が増えたことに増長して、ソースコードをたくさん載せたはいいのですが、それを説明する余白がありませんでした。今回は、前回掲載したソースコードについて、新しく使いはじめた部分を中心に説明します。
 その前に、連載を通じて少しずつではありますが、プログラムが拡張してきましたので、プログラム全体がどのような構成になっているかを、一度立ち返って見直してみます。ある程度の開発規模になってくると、設計図なく開発をすることは困難になってきます。今後のさらなる拡張と改良もふまえて、設計図を作って開発を進めていきます。

記事本文掲載のシェルスクリプトマガジンvol.48は以下リンク先でご購入できます。

UNIXネイティブの電子工作塾 vol.48掲載

投稿日:2017.05.23 | カテゴリー: 記事

著者:金沢大学 教授 大野浩之

さて、UNIXネイティブの電子工作塾 e-Badge編第2回ですが、少しだけ回り道をすることにました。今回は e-Badge(電子名札) のためのプリント基板(PCB)作りに着手する予定でしたが、その前にお話しておくべきことがありました。まず、PCB設計に用いるソフトウェア “Fritzing” の特徴をお伝えしたいと思います。それから、Fritzing で作成したPCBデータがどのようなもので、 これをどこにどうやって発注するのか、といったノウハウもお伝えしたいと思います。
そこで今回は、e-Badge の製作をはじめる前に、よりシンプルで汎用的な基板を作ることにしました。

本記事掲載のシェルスクリプトマガジンvol.48は以下リンク先でご購入できます。

ユニケージ開発手法 コードレビュー vol.37(本誌vol.48掲載)

投稿日:2017.05.23 | カテゴリー: 記事

著者:USP研究所技術研究員 新美勇一

今回は、業務システムの処理に見立てた簡単な例題で2つ実装例を挙げ、レビューを行いたいと思います。

本記事掲載のシェルスクリプトマガジンvol.48は以下リンク先でご購入できます。
USP研究所 通販サイトでは、個人用uspTukubaiのご購入も可能です。

バーティカルバーの極意 第二回 (vol.48掲載)

投稿日:2017.05.23 | カテゴリー: 記事

著者:中央大学 教授 飯尾淳

 バーティカルバーの極意、連載2回めの今回は、対象とするバーティカルバーとして「棒グラフ」を取り上げます。より正確にいえば、棒グラフのなかでも、ヒストグラムとよばれる種類の棒グラフです。ヒストグラムを柱状グラフと呼ぶこともあります。一般的に、柱はまっすぐ垂直に立てられるものです。この名称ひとつとっても、ヒストグラムをバーティカルバーの一族と考えてかまわないでしょう。

記事本文掲載のシェルスクリプトマガジンvol.48は以下リンク先でご購入できます。

/'”${LF}”‘/g’ | \ > grep ‘^20[01][0-9]年’ | grep UTC | \ > grep ‘日 [234]:’ | less

逆に、Tukubaiコマンドをシェルスクリプトで実装してみる 後編 (vol.48掲載)

投稿日:2017.05.23 | カテゴリー: 記事

著者:今泉光之 (Twitter: @bsdhack)

Open usp Tukubai は Python により実装されているので Python が動作する環境であればインストール可能です。
公式の配布サイトからソースを取得して展開し make install するだけで Open usp Tukubai は利用可能となります。
ここでは Open usp Tukubai のコマンドを解説します。
ただし以下のように Open usp Tukubai だけでも 55 コマンドも提供されており、その全てを解説するのは無理なので、
特に有用で興味深いコマンドを厳選して紹介します。

前回紹介したcalclock、comma、getlast、ketaに続き、今回はmojihame、self、sm2の3つのコマンドを紹介し、シェルスクリプトでの再現を試みます。
但し今回は紙面と時間の都合で一部の機能やオプションなど実装できていない部分も多いです。
また、動作の把握とメイン処理の実装のみに絞ったので、エラー処理などはまったく実施していません。
そのために実際の業務などには殆ど利用できない実験的なスクリプトとなっています。

mojihame

mojihameとは

テンプレート中に埋め込まれたキーワードをデータに置換して出力します。
キーワードは %数字 の形式で指定し、データ中に出現した順番にテンプレート中の %1、%2 …と置換されます。
データ中の @ はヌル文字として扱われ空文字列に置換されますが -d オプションで @ を別の文字に変更できます。
データ中の _ はスペースに変換して出力されます。_ を出力したい場合は \_ の様に指定します。

-l オプションは行単位での置換処理が実施されます。
入力データは行単位に読み込まれ、入力データの次の行が読み込まれるとテンプレートは先頭から再利用されます。

-l オプションではラベルを指定することができます。
ラベルが指定された場合、テンプレート中でラベルの間に書かれたキーワードのみが置換の対象となります。なおラベルはテンプレート中で2回 (開始と終了) しか書くことができません。
(-h による階層構造に関しては説明が複雑なのでここでは省略します)

mojihameを作ってみよう

基本的な機能は全て awk(1) の組み込み関数で実装しました。
通常モードでは、 awk(1) の BEGIN 処理でデータを全て読み込み配列 data に格納した後で _ の置換処理を行っています。
メイン処理ではテンプレートファイルを読み込み、 match 関数を利用して %数字 のラベルを探して gsub 関数で置換しています。

行モードでは、 BEGIN 処理でテンプレートを全て読み込みハッシュ template に格納しています。
メイン処理では、データを読み込み index 関数を利用して %数字 のラベルが存在する間テンプレートを置換します。
テンプレートに数字のラベルが見付からない場合は、テンプレートの次の行をハッシュ template から取得して処理を続けます。

今回紹介した Tukubai コマンドの中では、これが一番多機能なコマンドでした。非常に複雑で多機能なので、通常モードと行モードの基本的なテンプレート置換機能しか実装しておらず、-l オプションのラベル指定、-h オプションによる階層構造テンプレートなどは実装していません。

self

selfとは

入力データ(ファイルや標準出力)の指定されたフィールドのみを出力します。

フィールドの指定時のオプションで、開始文字と文字列長が指定できます。
例えば 4.3 とした場合は第 4 フィールドの 3 文字目から出力され、5.5.4 とした場合は第 5 フィールドの 5 文字目から 2 文字が出力されます。
マルチバイトの文字の場合、開始文字と文字列長はそれぞれ 1 文字を 2 として計算する必要があり、
マルチバイト文字を文字の中間で分割する様な指定された場合はエラーとなります。

フィールド指定の 0 は全フィールドを表します。
フィールド指定で n/m (n と m はそれぞれ整数) とすることで n 番目から m 番目のフィールドを出力できます。
フィールド指定の NF は現在行のフィールド数に置き換えられ NF-3 (最後から3番目のフィールド) や 2/NF などの利用が可能です。

-d オプションは引数で指定した文字列を区切ることができます。

selfを作ってみよう

self コマンド自体が awk(1) と似ているので、多少冗長になってしまいましたが awk(1) の機能だけで殆ど実装できました。フィールド指定、NF による相対的なフィールド指定、NF からの相対位置による指定、n/m 指定などが動作しています。
ただし OS X 標準の awk(1) はマルチバイト文字には対応していないのでマルチバイト文字を扱うことができません。
Linux で標準的に利用されている GNU awk の場合はマルチバイト文字に対応していますので、今回作成した self コマンドも正しく動作しています。

(次ページに続く)

もしインターネットの1秒が1年だったら 第1回(vol.47掲載)

投稿日:2017.05.16 | カテゴリー: 記事

written by hakatashi・Mine02C4

編注:本記事は「SunPro 2016 技術書典」で発表された記事に説明・イラストを追加し、シェルマガvol.47に掲載したものです。
以下リンク先で、オリジナル版の全文が公開されています。
https://sunpro.io/techbookfest/

インターネットが日本中のあらゆる人間に行き渡るようになってから、すでに10年単位の時間が経過しています。今日においてインターネットを支えるネットワーク技術が重要であることは言うまでもありませんが、実際にネットワークでどのタイミングで何が起こり、どれくらいの時間が費やされるのかということを身を持って体感している人は、たとえネットワークに精通している人でも少ないのではないでしょうか? この記事では、1 秒というわずかな時間を1年にまで拡大し、ネットワーク上で何が起こっているかを人間スケールでざっくりと解説していきます。

はじめに

こんにちは。先号まで石川啄木を蘇らせようとしていた博多市(@hakatashi) です。今回から、2016年の技術書典にSunProとして発表した「インターネットの1秒がもし1年だったら」というだいぶ抽象的で怪しい記事を、シェルスクリプトマガジン向けに再構成してお届けします。
インターネットというのは光の速さを身をもって感じることができるメディアです。先日、Hiraku Nakanoさんの「composerの遅さをまじめに考える」というスライド*1を拝見したのですが、そこではPHPのパッケージマネージャーであるcomposerが遅い原因として、「光の速さが遅すぎる」という理由が挙げられていました。
ユニークな考え方ですが言われてればたしかに道理で、日本からアメリカのサーバーまでハンドシェイクで何度も往復していると、確かに光といえど100ミリ秒単位で時間を浪費しています。
サーバーが近ければ通信は早いというのは誰もが知っていることですが、光の速度のせいだと言われるとなにやら圧倒されるものがあります。
この記事では、そんなネットワークの微視的な時間スケールについて徹底的に解剖します。一回の通信を解析し、それぞれ時系列順に細かく分解し、それぞれの操作でどれくらいの時間が費やされ、どんなイベントがいつ発生するのかを逐一追っていきたいと思います。
とはいえ、ネットワーク通信における時間経過はミリ秒単位で数えられます。今回は、そんな微細な時間の移り変わりをなるべくわかりやすくするため、通信上の1秒という時間を1年にまで引き伸ばし、約3000万倍の時間スケールでネットワークのイベントを追跡してみます。

*1 http://www.slideshare.net/hinakano/composer-phpstudy

共著者について

本記事の筆頭筆者はhakatashiですが、今回の記事を書くにあたり、同じSunProメンバーでありネットワークスペシャリスト取得者のMine02C4*2から、企画段階からの多大な協力と大幅な加筆を得ることができました。
ネットワーク知識不足のhakatashiにパケット解析を指南し、本記事では特にTLS 関連の項目の執筆、および全体のレビューを担当しています。共著者として名を連ねていますが、彼の協力なしでは本記事は恐ろしくクオリティの低いものになったであろうことは疑いようがなく、その貢献度に関しては計り知れません。どうぞお見知り置きください。

*2 HP: http://mine02c4.nagoya/, Twitter: @mine_studio

シチュエーション

今回解剖する対象の通信として、HTTPSによる通信をメインに解析しました。ふだん我々がブラウザから毎日使っているプロトコルなのは言うまでもなく、SSL/TLSの処理を挟むので、それなりに面白い結果になるのではないでしょうか。
また、HTTPS通信を行う際に必要となるARPやDNS通信についても述べていきます。さらに、通信を行うサーバーとクライアントの場所ですが、今回は、技術書典の会場でもある東京のインターネット環境から、さくらインターネットが誇る、北海道の石狩データセンターまでの通信を行います。
Googleマップによると、東京から、石狩データセンターがある石狩市新港中央までは1177.3km。光ファイバーに用いられる石英ガラスの屈折率は1.50程度*3なので、光は約20万km/sでこの距離を移動します。つまり、東京から石狩までの物理的な片道時間は約5.9ミリ秒となります。瞬く間もないほどの時間ですが、時間スケールを1年に引き伸ばすと2日と3時間半もかかります。往復で4日と7時間。石狩までぶらり旅といった感じですね。

*3 光学ガラス材料- シグマ光機株式会社

1秒 → 1年

1秒が1年になった世界の様子をもう少し見てみましょう。
真空中の光は時速34kmで移動します。先ほど出てきた光ファイバー中の光速は時速23km程度になるので、自転車か、休憩しながらのドライブ旅程度の速さになります。ちなみに男子マラソンの世界記録は時速20.6kmです。*4*5
3GHzのCPUは、こんな世界でも1秒間に95回という高橋名人の6倍のクロックを刻みます。PC3-12800のメモリーの転送速度は、もはやダイアルアップ接続よりも遥かにナローバンドですが、最大で1秒間に3200ビットの情報を読み出すことができます。

*4 2014年ベルリンマラソンのデニス・キメット選手の記録、2時間2分57秒より。
*5 ただし、この速度で走行するとこの世界では体重が26% 増えるのでオススメしない。

制約など

今回パケットを解析する上で、話を簡便化するためにいくつかの制約を加えています。
● DNSのシステムを明確に示すため、ローカルホストにDNSサーバーを置き、そこからリクエストのたびにルートDNSサーバーからアドレスを引いています。
● 複雑かつ時間がかかりすぎるため、ネームサーバーでのDNSSECの検証処理は無効化しています。
● SSL/TLSの証明書検証処理は無効化しています。

測定環境

測定には、ラップトップマシン上のUbuntuの仮想環境を使用しました。一回の測定ごとにDNSキャッシュとARPキャッシュをクリアし、なるべくクリーンな状態で測定を行いました。
また、先程も述べたとおりDNSサーバーはローカルホストに設置し、そこから外部に向けてアドレスを引くようにしました。
サーバーは先ほど述べたさくらの石狩データセンターへのアクセスを確実に測定するため、今回の記事のためにさくらVPSの石狩リージョンのサーバーを調達しました。OSはさくらVPSの初期OSであるCentOS 6.8で、デフォルトのApache 2.2.15をほとんどそのまま使用しました。SSL は自己署名証明書で通信し、証明書の検証は無効化してあります。
クライアントは、Windows上の仮想マシンのUbuntu 14.04.4を用いました。クライアントアプリケーションはcURLを用いています。ネームサーバーはローカルホストにBIND 9.9.5を立て、キャッシュを無効化した上でルートサーバーからアドレスを引くよう設定してあります。
通信内容は、100KB(102400 バイト)のバイナリファイルをGETリクエストで取得するもので、HTTPパラメータはほぼcURLのデフォルトを使用しています。
パケットキャプチャはクライアント側とサーバー側で同時に行い、tcpdumpで同じ通信を2度キャプチャして解析しています。時刻に関しては毎度NTPで時刻補正しましたが精度が得られなかったのでサーバー側とクライアント側の測定値を見て適当に補正を行いました。
今回記事中で使用した数字は、以上の条件のもとに行った10回の測定結果の平均値をもとにしています。

サーバーちゃんとクライアントちゃん

サーバーちゃん   クライアントちゃん

今回、せっかく時間軸を人間スケールで語るので、通信処理の登場人物も人間という体で解説していきます。
この話の主人公は「クライアントちゃん」と「サーバーちゃん」です。クライアントちゃんは東京で悠々とした生活を送っている普通の女の子であり、趣味は暗号と文通です。一方サーバーちゃんは石狩のデータセンターで、ひしめき合うたくさんのサーバーとともに、Webサーバーとして多忙な毎日を送っています。
こんな対称的な2人が、今回は年明けと同時に通信を開始します。さらに、通信は手紙のやり取り、IPアドレスは住所、ルーターは郵便ポスト……というように、適宜シチュエーションに合わせた読み替えを行っていきます。あくまで例えですので、あまり正確ではないかもしれませんが、今回の目的はあくまで通信処理の全貌をふわっと理解することなので、あまり厳密に考えず、空っぽの頭で読んでください。
また、今回解説する通信処理の概略を、簡単なシーケンスダイアグラムで示します。通信処理の主役は情報をやり取りするサーバーちゃんとクライアントちゃんなのですが、第1回は2人の通信が開始するまでの準備作業が主となり、サーバーちゃんはまだ登場しません。インターネット通信において目的のサーバーのアドレスを見つけるためにどのような処理が行われているのかを一段階ずつ検証していきます。


それでは、クライアントちゃんとサーバーちゃんの通信の始まりです。

 

ルーターのアドレス解決

1月1日 午前0時0分 ARPリクエスト送信

あけましておめでとうございます。NHKの「ゆく年くる年」を見ながらインターネットの年が明けます。
この瞬間、東京でまったりと紅白歌合戦を見ていたクライアントちゃんは、石狩にいるサーバーちゃんに聞きたいことがあるのを思い出しました。長い長い通信の始まりです。
さっそくクライアントちゃんはサーバーちゃんに手紙を書くことにしました。
クライアントちゃんは何もわかりません。郵便ポスト(ルーター) の場所も、サーバーちゃんの住所(IPアドレス) も、いつも使っていた住所録(DNSサーバー) の場所も覚えていません。
キャッシュを削除したクライアントちゃんは記憶を失ってしまったのです。
覚えているのは、ただ石狩にいるはずのサーバーちゃんのことだけ……。
困ったクライアントちゃんは、まずは郵便ポスト(ルーター) を探すことにしました。家の中や向こう三軒両隣のことならともかく、遠く石狩に住むサーバーちゃんに手紙を届けるには、何よりポストがなければ話が始まりません。
クライアントちゃんはもうネットワークに接続しているので、ルーターのIPアドレスはすでに分かっています。しかし実際にルーターと通信するには、ルーターのMACアドレスが必要です。これを引くために、ARP(Address Resolution Protocol)と呼ばれるプロトコルを用います。
ARPリクエストはIPアドレスに対応するMACアドレスを検索するリクエストです。MACアドレスのプロードキャストアドレス(FF:FF:FF:FF:FF:FF) に向けて発信することで、同一ネットワーク内のすべての機器にこのリクエストを送信することができます。クライアントちゃんは街中に響く声でポストの場所を尋ねました。

「郵便ポストはどこですかぁぁぁぁ??!!」

1月1日 午前3時26分 ARPレスポンス受信

いったい今何時だと思っているんでしょうか。クライアントちゃんの声は街中に響き渡り、近隣住民からたいへん大目玉を食らいましたが、努力の甲斐あって、3時間半後に親切な人がポストの場所を教えてくれました。
ARPは、ブロードキャストでネットワーク全体に配信されたイーサネットフレームに対して、尋ねられているIPアドレスが自分のものであればMACアドレスを応答するというシンプルな仕組みで動作します。
今回は事前にARPキャッシュを削除してから通信を行ったので、通信前に必ずARPの問い合わせが走るようにして計測したのですが、そもそもARPは頻繁にキャッシュを消去します。*6クライアントちゃんはとても忘れっぽいのです。

*6 Ubuntu の場合、キャッシュの有効時間は15 分程度。

DNS解決

1月1日 午前5時7分 DNSクエリ送信 1回目

親切なおじさんのおかげで、クライアントちゃんは郵便ポストの場所を知ることができました。
またすぐ忘れてしまうのですが、この世界では約900年後のことなので、特に気にすることはありません。
となると次にクライアントちゃんが知るべきはサーバーちゃんの住所(=IPアドレス) です。郵便ポストを見つけても相手の住所がわからないと手紙は送れません。サーバーちゃんの住所を知るために、クライアントちゃんはルートサーバーに住所を問い合わせることにしました。
電話番号に電話番号問い合わせサービスがあるように、ネットワークの世界にも、ドメイン名から相手のアドレスを問い合わせるためのDNS(Domain Name Service)があります。
電話番号の場合は104番という番号を知っていれば他の番号を問い合わせることができます。
インターネットにおける“104”は、世界に13個存在するルートサーバーのアドレスです。今回は、13個の中で唯一日本の団体が管理している、Mルートサーバーに問い合わせるようにルートサーバーの設定を変更しています。*7
サーバーちゃんの住所を一秒でも早く正確に知りたいクライアントちゃんは、世界中に数あるDNSサーバーの中でも最も権威あるルートサーバーに一筆したためることにしました。あらゆるキャッシュを削除したクライアントちゃんも、一番大事なルートサーバーの住所は覚えています。
あれこれ悩んで手紙を書き、ようやく完成したのはそれから1時間半後のことでした。早朝の冷たい冬風が骨身に染みます。クライアントちゃんはコートを厚めに羽織ってポストに手紙を投函しに行きました。
一刻も早く返事が帰ってくることを願って……。

「うぅっ、さぶっ。早くお返事来るといいなぁ」

*7 もっとも、ルートサーバーはクラスタ構成になっており国単位で分散しているため、必ずしも問い合わせたマシンが日本に存在するかどうかは保証されないのですが…。

1月14日 午前3時57分 DNSレスポンス受信 1回目

最初に手紙を送ってから2週間が経過しました。冬休みも終わって正月気分もようやく抜けてくる頃です。もうこの時点で直接会いに行ったほうが手っ取り早いんじゃないかという気がしますが、石狩は遠いのです。そんな気軽に会いに行けないのです。たぶん。

ともあれ、ルートサーバーからようやく返事が帰ってきました。郵便局が怠慢なのかルートサーバーがお役所仕事をしてるのか知りませんが、とにかくこれでサーバーちゃんの住所を知ることができた……というわけではありません。
ルートサーバーは世界中のすべてのマシンのIPアドレスを記録しているわけではありません。
ドメイン名を問い合わせられたDNSサーバーは、自らが委任するDNSゾーンのネームサーバーの情報を返します。今回問い合わせたドメイン名はさくらのVPSサーバーにデフォルトで割り当てられたドメイン*8なので、ルートサーバーはjpサブドメイン*9のネームサーバー*10を返してきました。つまりjpドメインのことはjpドメインの担当者に聞けということです。

「えー……」

*8 .vs.sakura.ne.jp で終わるドメイン名
*9 .jp はTLD(Top Level Domain) なのでサブドメインと呼んでいいか微妙ですが……
*10 a.dns.jp, b.dns.jp, c.dns.jp, d.dns.jp, e.dns.jp, f.dns.jp, g.dns.jp の7 つ

1月14日 午前9時52分 DNSクエリ送信 2回目

jp ドメインの担当者というのは要はJPRS(日本レジストリサービス)のことです。サーバーちゃんの住所を聞き出す手がかりを得たクライアントちゃんは、夜が明けるのを待ってから今度はJPRSのDNSサーバーに対して手紙を書きました。
実を言うと、jpドメインのネームサーバーを管理しているのはJPRSその人ですが、実際の運用は、JPRSを含めた5つの独立した組織によって行われています。これはルートサーバーが世界に13個あるのと同じく、ネームサーバーがダウンした際のリスクを可能な限り最小限に抑えるためです。
2 回目のDNSレイヤーの内容は、トランザクションIDを除いて前回ルートサーバーに対して送ったのと全く同じ内容です。DNSはなるべく高速に動作するように簡明に設計されているため、このようにパケットの内容を容易に再利用できるようになっています。決してクライアントちゃんがサボっているわけではありません。

1月27日 午後2時30分 DNSレスポンス受信 2回目

ふたたび待つこと2週間。すでに1月が終わりに近づいてきました。
クライアントちゃんの元にJPRSからの返信が届きました。サーバーちゃんの住所はまだわかりません。今度はsakura.ne.jpの権威サーバーである、さくらインターネットのネームサーバー*11の情報が返ってきました。

「……またかよ」

ここに来てようやくさくらインターネットの影に辿り着きました。サーバーちゃんの住所ゲットまであと一息です。

*11  ns1.dns.ne.jp, ns2.dns.ne.jp

1月27日 午後6時56分 DNSクエリ送信3回目

同じやり取りも3回繰り返すと飽きてしまいますね。けれどクライアントちゃんはサーバーちゃんに手紙を届けるために、めげずにDNSのパケットを送り続けます。今度は先ほど入手したさくらインターネットのネームサーバーの住所に対して、みたびサーバーちゃんの住所を尋ねる手紙を出します。
ところで、先ほどからクライアントちゃんは気軽にあちこちにDNSパケットを送ったり受け取ったりしていますが、これはDNSがUDPプロトコルの上で動作しているからです*12。UDPは、後ほど解説するTCPと異なり、相手のマシンとの接続を確立する必要がないため、気軽に任意のアドレスにいきなりデータを送りつけることができます。
逆に言うと、TCPのような再送要求やエラー訂正などの機能を持たないため、伝送経路のどこかでパケットが損失した場合、クライアントちゃんは返事を待ちぼうけということになってしまいます。
もっとも、それもタイムアウトするまでですが。

*12 DNS自体はTCP上でも動作することが義務付けられています。

2月10日 午前9時35分 DNSレスポンス受信 3回目

2月に突入しました。幸い3度目のクエリも待って待って待ちぼうけという事にはならず、ポストに投函してから2週間経って再び返事が帰ってきました。そこには待ち望んでいたサーバーちゃんの住所がくっきりと書かれています。
これにて名前解決完了。ようやくサーバーちゃんに対してパケットを送りつけることができるようになります。もうあちこちのネームサーバーとパケットをやりとりする必要はありません。年が明けてから41日間、実時間にして110ミリ秒が経過しました。この調子で年内にサーバーちゃんとの通信を終えることができるのでしょうか。クライアントちゃんの通信はまだまだこれからです。

「この続きはシェルマガvol.48、またはオリジナル版掲載サイトを見てねっ!」

本記事掲載のシェルスクリプトマガジンvol.47は以下リンク先でご購入できます。

漢のUNIX ライブラリをつくってみよう! #その3(vol.46掲載)

投稿日:2017.05.9 | カテゴリー: 記事

著者:後藤大地

今回は分割したファイルが実際にどのように処理され、最終的にバイナリ形式の実装ファイルに変換されるのかといった過程を、もうちょっと詳しく紹介していこうと思う。実際にどのように処理が進むのか知ることで、コーディング中の頭の中にどのように処理されるのか地図が浮かんでくるようになり、より効率が良く見通しの良いソースコードを記述できるようになる。その内側を調べていこう。

 

記事本文掲載のシェルスクリプトマガジンvol.46は以下リンク先でご購入できます。