図3●OSIの参照モデルとソケット
実際の通信は階層状に積み重なった複数のプロトコルを利用して実現している。例えばダイヤルアップ接続でWebを閲覧するには,物理層はRS-232C,データリンク層でPPP(Point-to-Point Protocol),ネットワーク層でIP,トランスポート層でTCP,セッション層~アプリケーション層でHTTPを利用して通信している。例えばDelphiを使ってWebブラウザを作ろうとするなら,HTTPを使った通信の段階までライブラリを利用できる。一方TCP/IPを使ったネットワークで,適当なクライアント-サーバー型のアプリケーションを作るならば,ソケットを利用することになる。ソケットがTCP/IP以下の操作を隠蔽してくれる。どのようなデータをやり取りし,どう解釈するかというアプリケーション・レベルのプロトコルさえ決めておけばよい。

複数のプロトコルが積み重なる

 一方,インターネットを初め,LANなどでも使われているTCP/IPでは「ソケット」を通じて通信する。LinuxやUNIX,WindowsなどほとんどのOSが標準でソケットを実装している。またJavaやVisual Studio .NET,Delphiなど,多くの言語処理系はネットワーク・プログラミング用にソケットを操作するクラスを提供している。

 ソケットがどういうものなのか説明する前に,プロトコルの階層構造について説明しておこう。よく「プロトコル・スタック」などと呼ばれるように,実際の通信はさまざまな層におけるプロトコルを使うことによって成り立っている(図3[拡大表示])。例えばシリアル通信ではRS-232Cがハードウェア層に相当するし,LANではイーサネットがよく使われている。一方TCP/IPというのは,OSIの参照モデルで言えばトランスポート層とネットワーク層に相当する。だからこの下のレイヤーでPPP(Point-to-Point Protocol)とRS-232Cを組み合わせれば,ダイヤルアップ接続のIPネットワークに接続できる。またWebブラウザが使っているプロトコルであるHTTPは,アプリケーションが送られてきたデータを解釈する方法をまとめたものである。

 この中にソケットを当てはめてみる。ソケットはTCP/IPを利用して通信する際のデータの出入口だから,プロトコルのレイヤーで見るとトランスポート層より下を隠蔽するものだと考えられる。もっと単純に言えば,ソケットはちょうどTCP/IPまたはUDP/IPを利用するためのAPIと考えていい注5)

ポート番号も一種のお約束

 ソケットは,IPアドレスとポート番号によって接続する先を切り替える。IPアドレスは通信相手のコンピュータの所在地を識別するのに使う。ポート番号は,通信相手のアプリケーションの種類を識別するのに使う(図4[拡大表示])。もともとポート番号は,1台のコンピュータでさまざまな種類の通信をこなすために導入されたものだ。1台のコンピュータが複数のコネクションを張るためには,コネクションを識別できないとどこの誰に反応するのかがわからなくなってしまう。コネクションを識別するのに導入されたのがポート番号である。これらのうち,WebサーバーやFTPサーバーなど,サーバー・アプリケーションとして一般的に使われるものはデフォルトでポート番号が決まっている。実際にはこのポート番号でなくても利用可能だ。たまにWebサーバーによっては8080番を使っていたり,Webブラウザを使った管理プログラムが5000番台のポートを使っていたりするのはこのためだ。

図4●ポート番号の概念
ソケットを利用した通信は,アプリケーション・レベルのプロトコルを関知しない。ポートはデータの入出力場所であり,複数の通信を同時に実行するためのものだ。通信相手の識別に使う。インターネットのように不特定な相手との通信を実現するため,特定のアプリケーションが利用するポート番号を決めているものがある。Webサーバーの80番や,FTPの20,21番などが有名だ。こうすることにより,任意の相手との通信が可能になった。

ソケットも基本は無手順通信

 ソケットを使った通信は,TCP/IPのレイヤーでセッション管理などはしているものの,アプリケーション・レベルから考えれば無手順のシリアル通信とほぼ同等である。基本的にデータは,ソケットを通じて直列に並べられたイメージで伝達していく(図5[拡大表示])。例えばHTTPでのやり取りをみると,クライアントが「GET ファイル名 HTTP/1.0」などと送ると,ファイルの内容を転送する。データは列状に変換されて(シリアライズ),ソケットを通じて流れていく(写真1[拡大表示])。このように列状の情報として管理できるので,ファイルとネットワークを等価に取り扱うことも簡単である。

 ソケットを使ったネットワーク・プログラミングの仕組み自体は,シリアルポートを使った通信とほとんど変わらない。

 基本的に通信プログラムの動作モデルは,前述のように2種類のイベント(ユーザー操作に関するものとデータ受信)から成り立っている。つまり,ソケットでデータを受信したというイベントを受け取るか,常にデータの受信状態を監視しているかという二つの手法が考えられる。これは,その言語処理系の実装に依存する話だ。例えばDelphiのソケット通信用クラスでは,データを受信したときにイベントが発生して通知してくれる注6)。Javaを使う場合は,別スレッドでデータの受信に専念させることによって随時受信を監視させることができる。

図5●データは一直線の“流れ”に
ネットワークを通じてデータを送受信するとき,各ノードでデータを一連の流れに変換してからやり取りする。ソケットを通じてつながったコンピュータ間は,1本の細い線で結ばれていると理解すればいいだろう。データの位置や並び順などは,アプリケーション・レベルのプロトコルによって規定されている。これに従ってデータを解釈するのだ。
 
写真1●ソケットを使ってWebサーバーにアクセスしたところ
接続先のIPアドレスとポート番号を指定して,ソケットを開く。HTTPプロトコルにしたがってリクエストを送信すると,ファイルの内容が転送されてくる。

「ふうん。じゃぁ,私でもソケットを使えば通信できるわけですね」
「もちろん。HTTPとかならば,DelphiにしろJavaにしろ.NETにしても,標準でプロトコル・ハンドラもあるから,簡単なデータ取得プログラムくらいならすぐに書けるよ」
「この間,書いてましたよね」
「一度のたくさんの手間を取るか,たくさんのちょっとの手間を取るか。人間系のエラーをなくすには,前者の考え方を採るべきだと思うんだ。だから,ちょっとしたことでも繰り返しがあるならプログラムを作ろうと思うんだよね。まあ,結構簡単だったってのも理由だけどさ」
「簡単なんですか」
「通信のところは,気を付けるべきことはたくさんあるけど,そんなに難しいこっちゃないよ」

(北郷 達郎、八木 玲子)