Pages

2012年1月15日日曜日

WebSocketのRFCを一寸だけ訳す

HTML5と共に気になる技術があります。WebSocket。TCPソケット通信をHTTPプロトコルの下で実現する技術であり、試みだと想像しています。XMLHttpRequestを利用するAjaxは、ドキュメント全体の更新で高負荷となるHTTPと異なり、初めて観た時に革新的だった。でもプログラムレベルでは、やっぱりなじまない。もう少し、他の部分とは独立的にTCP送信を実装したいもんだと、WebSocketに期待しています。
そのWebSocketですが、RFCが公開されていたので、さわりの部分だけ訳してみました。

原文は、ここです。
http://tools.ietf.org/html/rfc6455

いやあ、酷い和訳です。あくまで自分の勉強のためなので、決して訳を鵜呑みにしないように。そもそも、日本語になっていないような気もするし、概要と導入部の最初の節だけなので、具体的な内容には乏しい。

ウェブソケット プロトコル

概要
ウェブソケット・プロトコルは、管理された環境で委託されたコードが動いているクライアントと、そのコードが通信を受け取っているホストとの双方向通信を可能にします。
セキュリティモデルは、ウェブ・ブラウザに一般に使われている原初的なセキュリティモデルです。プロトコルは、T通信を開始時の通信確定手順と、それに続くTCP層の基本的なメッセージ・フレーム群で構成されています。
この技術の狙いは、サーバとの双方向通信を必要とするブラウザベースのアプリケーションに、XMLHttpRequest、iframe、ロング・ポーリングのような複合的なHTTP接続に頼らない、機構を提供することです。

1. 導入(イントロダクション)
1.1. 背景
歴史的に、クライアントとサーバ間の二方向の通信を必要とするウェブアプリ(チャット、ゲームとか)は、更新確認のため、上位への通知を送信する間、(ドキュメントの表示のためのHTTPではない)別のHTTPコール(RFC6202)を使ったサーバへのポーリングを多用してきた。

この結果は、様々な問題を生むことになる。
* サーバは、それぞれのクライアントと、クライアント数だけのTCP通信を強いられる。ある通信は、クライアントに情報を送り、またある通信は送られてくるメッセージを受け取るために。
* 通信の成立は、非常に負荷が高い。それぞれのクライアントーサーバ間メッセージは、(そのための)HTTP headerをメッセージ毎に持っている。
* クライアントサイドスクリプト(Ajaxのような)は、送信結果を結びつけるために、送信と受信の管理(マッピング)を強いられる。

より単純な解決は、双方向の流れをまとめた一つのTCP接続を使うことであるべきだ。これが、ウェブソケットプロトコルの提供するものだ。WebSocket APIを組み込むことで、ウェブプロトコルは、ウェブページから、遠隔地のサーバへの双方向通信を実現するため、HTTPポーリングに代わる別の手段を提供する。
同様の技術は、様々なウェブ・アプリケーションで使われることが可能だ。ゲーム、リアルな証券情報ニュース、複数人による同時編集アプリ、リアルタイムな情報発信機能を提供するユーザインターフェースなどなど。

ウェブソケット プロトコルは、現存する基盤(プロキシ、フィルタリング、認証)からの利便性を得るために、トランスポート層でHTTPを利用している現存の双方向通信技術を捨て去ることができるように設計されました。

== このあたり、全くお手上げ ==
そのような(現存の)技術は、効率と信頼性のトレードオフのもとで実装されている。なぜなら、HTTPは、本来、双方向通信に利用されることを意図していなかったからである。
ウェブソケットは、その目的を、既存のHTTP基盤のもとで、既存のHTTP双方向通信技術に割り当てている(?)。それは、80ポートや443ポートで動作することで、HTTPプロキシや媒体(それが、現在の環境への特殊な使用を意味することであっても)をサポートすることだ。
「 The WebSocket Protocol attempts to address the
goals of existing bidirectional HTTP technologies in the context of
the existing HTTP infrastructure; as such, it is designed to work
over HTTP ports 80 and 443 as well as to support HTTP proxies and
intermediaries, even if this implies some complexity specific to the
current environment.」
== ここまで ==

しかし、設計では、ウェブソケットをHTTPのみに制限していないし、将来の実装では、全体のプロトコルを再構成する事無く、専用のポートのもとで、より単純な通信確定を使うことが出来る。
最後の点は、重要である。なぜなら、双方向のメッセージ通信の際の交信パターンは標準的なHTTP交信にぴったりとはあっていないし、いくつかのコンポーネントの一寸変わった取込を実現できるからだ。

2011年12月25日日曜日

iTunesはXMLで出来ている (1) DTD読み込み編

iTunesのライブラリ管理は、xmlファイルで行われています。なんとか、加工してみたいと思い、XMLの勉強をし直してみた。
# この記事は、ちょっと(いつもの通り)中途半端です。申し訳ない。

いまさらXML

XMLと一言でいっても、中は結構複雑、その世界は4つの技術で構成されている。
  • 構造記述言語 XML
  • 変換言語 XSLT
  • リンク言語 XPointer
  • 問い合わせ言語 XPath
iTunes管理ファイルを加工する手続きを上記の4つの技術を使って説明すると以下のようになる。
XMLで記述されたファイルiTunes.xmlを、XSLTで目的のhtmlに変換する。
XSLは、必要な個所をXPATHを使って探し出しXPointerが取り出す。

iTunes Music Library.xmlの構造

ライブラリを管理しているファイルitunes Music Library.xmlは、私のMac OSXの場合、以下の場所にある。実際には、ライブラリを移動している人もいますから、検索したほうが良い。

~/Music/iTunes/iTunes Music Library.xml
# windowsではどこなのか知りません。:-p

各情報は、dictタグでくくられている。
各情報の要素は、Keyタグとその値の組み合わせで記載。
トラック情報の要素は、名前、
内容を、先頭のほうを覗いてみると
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Major Version</key><integer>1</integer>
  <key>Minor Version</key><integer>1</integer>
  <key>Date</key><date>2011-11-19T23:48:40Z</date>
  <key>Application Version</key><string>10.5.1</string>
  <key>Features</key><integer>5</integer>
  <key>Show Content Ratings</key><true/>
  <key>Music Folder</key><string>file://localhost/Users/baker/Music/iTunes/iTunes%20Media/</string>
  <key>Library Persistent ID</key><string>BB0A0B413A2028D8</string>
  <key>Tracks</key>
  <dict>
    <key>3708</key>
    <dict>
      <key>Track ID</key><integer>3708</integer>
      <key>Name</key><string>Time Difference</string>
      <key>Artist</key><string>Hiromi's Sonicbloom</string>
      <key>Composer</key><string>上原 ひろみ</string>
(以下略)
となっている。
DTD (Document type Definition 文書型宣言)として、http://www.apple.com/DTDs/PropertyList-1.0.dtd ファイルが指定されている。DTDは、このファイルが所属している文書の構造を定義しているファイル。構造とは、どんな要素から成り立っているか、特別に定義しているタグ(要素)はなにか、属性の書き方はどうなっているかとか、もろもろ。XMLは、共通する書き方があり、ほとんどのブラウザは、XMLとして正しい(Well formated)を判断してくれますが、文書の目的にそって正しく書いているかは、判断してくれません。当然です。そのルール(まあ、ローカルルールですな)を記載しているのが、DTDです。

最初のDOCTYPEコメント(文書型宣言)から、
"-" 企業のローカルな取り決めであり、Apple Computerが定めており、文書名は "DTD PLIST 1.0" (多分、Play Listなのかな)、Englishで書かれていますと言うことが判ります。

iTunes.xmlのDTDを取得してみると、以下のように単純です。
<!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" >
<!ELEMENT plist %plistObject;>
<!ATTLIST plist version CDATA "1.0" >

<!-- Collections -->
<!ELEMENT array (%plistObject;)*>
<!ELEMENT dict (key, %plistObject;)*>
<!ELEMENT key (#PCDATA)>

<!--- Primitive types -->
<!ELEMENT string (#PCDATA)>
<!ELEMENT data (#PCDATA)>
<!ELEMENT date (#PCDATA)>

<!-- Numerical primitives -->
<!ELEMENT true EMPTY>
<!ELEMENT false EMPTY>
<!ELEMENT real (#PCDATA)>
<!ELEMENT integer (#PCDATA)>

  • 実体宣言(ENTITY)で、plistObjectを定義しています。
  • "%plistObject"は、"array, data , dict, real , integer, string, true, false の何れか”と言う文字に置き換えなさいと言うことでしょうか。%記号は、宣言名であることを示しています。
  • 次の行で、要素(ELEMENT) plistの配下の構成(ノード)は、%plistObject だ定義しています。
  • さらに、plistは属性(ATTLIST) として、version をもちます。versionは、任意の文字列(CDATA)であり、初期値は"1.0"なんだそうです。
  • array要素は、配下に %plistObjectをもちますが、何回も繰り返しもって良いそうです。
  • dist要素は、配下に、%plistObjectとkeyをもち、これも繰り返しできます。
  • key要素は、任意の文字列を配下に持ちます。

こんなところでしょうか。

DTDを下に、再度 iTunes Music Library.xmlを眺めていると、なんか構造が見えてきた気がしませんか。
# plist (play list) Version = 1.0
# dict (dictionary? , 辞書? この場合、play list自身の属性)
  # key と %plistObject 要素で、playlist自身の内容を記載。
  # key "TRACKS" の中に、dictの集団がある。
      # dict メディアの情報
      # key トラック番号 integer 1
      # key  名前 string xxxxx
      ...
      ...
      # dict メディアの情報
      # key トラック番号 integer 1
      # key  名前 string xxxxx
      ...
      (繰り返し)

なんか、かえって判んなくなってきたかな。
次回は、htmlファイルにパースしてみる予定。

2011年12月4日日曜日

[Processing] 折り紙を折り続ける

前回の続き。1回しか折らない折り紙は哀しいので、折り続けさせてみた。

問題は、折った紙を新たに操作するときに、その座標とか折る方向とかをどのように計算するか。
あらゆる状況を想定する描写関数を用意するとか、再帰処理するかと考えたが、座標変換を利用してみることにした。

利用した関数は、
      transpate(x, y) --- 現在の座標をベクトル(x, y)分だけ座標を移動させる。
                          つまり過去の座標(x, y)が、新たな(0,0)となる。
      rotate( r )     --- 同様に r ラジアンだけ、軸を回転させ、あらたな座標にする  

期待した動きは、折りおわったら、translate し rotate(90度) して、新たな折り紙を左から右に折ることだった。

しかし、ここで落とし穴が。draw()関数は、座標をリセットする。何で? まだ信じられないのだが。
しかたないので、描写の度に translate , rotate を折り返しの数 実施させた。そのため、折りすぎると描写が遅くなってしまった。

でき上がったのは、以下のアプレット。
折り続ける折り紙

以下、ソースコードの解説
int cnt = 0;   // 折り返し回数
float rad = 270; // 折る角度

void setup(){
  size(200, 200);
  color(RGB,256);
  background(255);
  frameRate(30);
}

void draw(){
  // 折り紙の左上に座標を移動
  translate(50,50);
  float rr = 40;  // 折り紙の横の半分 (折りの半径になる) 
  float hh = 80;  // 折り紙の高さ
  // 折り回数分だけ、座標と半径、高さを計算し直す
  for(int i=0;i<cnt;i++){
    translate(rr, hh);      // 次の折り紙の左上
    rotate(radians(-90));  // 折りの方向を90度回転
    // 新たな折り紙の高さと半径(横の半分)
    float temp = hh;
    hh = rr;
    rr = temp / 2;
  }
  
  background(255);
  stroke(0);
  page(rr, hh, 90);  // 折り紙の右半分
  page(rr, hh, rad); // 折り紙の左半分 radは折り角度

  // 折り曲げたら折り角度radを戻し、1回カウント
  if(--rad == 90){
    rad = 270;
    if(++cnt > 5)cnt = 0; // 5回折ったら元に戻す
  }
}

// 開いた状態の折り紙の左上を 座標( 0,0 ) として
// 折り紙の左半分を描く
void page(float r, float h, float rd){
  // 折りの軸の上座標は(r, 0)
  float x = r + r * sin(radians(rd)); // 左上位置 X座標
  float y = 0 + r * cos(radians(rd)); // 左上位置 Y座標
  line(x, y, r, 0);         // 上辺
  line(x, y, x, y + h);     // 左辺
  line(x, y + h, r, 0 + h); // 下辺
  line(r, 0 + h, r, 0);     // 右辺
}

どうも、ロジックの正解は、
* 再帰関数を行う
* draw関数を使わない
のではないかと思う。もう少し調べてみる必要があるな。