第 3 日
5. iperf でネットワークのバンド幅を測定する
iperfコマンドは, ncコマンドと使い方が似ている. ただし目的はネットワークの性能(バンド幅)の測定であり,サー
バを立ち上げ,クライアントを立ち上げると勝手に10秒ほどデータを流して,ネットワークのバンド幅(転送速度)を表 示してくれる.
本課題 5.11 iperfコマンドを用いて,友達のマシンの間でバンド幅を測定せよ. たくさんの人(またはたくさんのプ
ロセス間)で同時に測定するとどうなるか. その状況で, ncで音声を流してみるとどうなるか?
第 6 日 ソケットプログラミング ( クライアント )
1. 概 要
いよいよネットワークを用いた通信を自前で行うプログラムの作成に入る. それにはUNIXでもWindowsでも, 標 準的に提供されている「ソケット」というプログラミングインタフェース(API)を用いる.
今回はソケットのクライアントを作るためのAPIについて説明する. 前回やったように,ソケットのクライアントは, あるポート上で「待ち受け」状態になっているサーバがいるという前提で,そのIPアドレスとポートに向かって接続す る(電話をかける). 接続後はデータの送受信(会話)ができる,という物である.
前述したとおりIPの上に構築されたプロトコルにUDPとTCPがあり,後者が信頼性(到達保証)を提供する. とり あえず最初はそちらが使いやすいだろうということで,以下の説明ではTCPを用いると仮定して具体的な説明をする.
TCPを使って実際に通信するための手順は以下の通り. 括弧内が実際に呼び出す関数名である. ステップ1: ソケットを作る(socket)
ステップ2: 接続する(connect)
ステップ3: データの送信(sendまたはwrite),受信(recvまたはread)を行う ステップ4: 通信終了後,ソケットを閉じる(close)
ファイル入出力との類推で言えば, socketはopenと似ている. send, recvはそれぞれwrite, readと似ている. 実際, sendの代わりにwrite, recvの代わりにreadを用いる事もできる. closeもファイルを閉じるときと実際に同じAPIを 用いる. つまりUNIXにおいてはソケットはファイルディスクリプタの一種なのである. 余分なステップはconnectと いう事になるが,これは別のプロセスに接続するという,ファイル入出力では必要なかった物だから,余分なステップに なるのもうなづける.
あえてもう少し実際のプログラム風に書けば以下のような手順になる. unsigned char data[N];
int s = socket∗();
connect∗(s, ”192.168.1.100”, 50000);
read(s, data, N); # dataにNバイトまでのデータを受け取る
data[0] =. . .;
data[1] =. . .;
. . .;
write(s, data, N); # dataからNバイトまでのデータを送る
close(s);
もちろんwrite, readは繰り返し用いても,どのような順番で用いても良い.
なお, UDP を用いる場合, 大雑把に言えば上記の connect というステップが省略され, send/recv のたびに
sendto/recvfromというAPI関数を用いる. sendto/recvfrom はsend/recvに加えて宛先のIPアドレス, ポート を指定する引数を持つ(つまり, TCPでは通信相手を前もって一つに限定しているのに対し, UDPでは送る度に自由に 宛先を変えることができるということである).
残念ながら実際のソケットAPIは引数などがもう少し多い上に, 名前もややこしい(上で関数名に∗をつけているの は,実際のAPIとは引数などが異なるという事を明示するため). あくまでそれぞれのAPIに渡している物は,上のよう な情報だという事を見失わないように,表面上のややこしさはある程度受け入れてもらうしかないのだが,なぜこんな事 になっているのかという事情説明を少ししておく. 「ソケット」はプロセス間で通信を行うための汎用的なインタフェー スとして設計されている. IP通信だけを対象としているのではない. 例えば同一ホスト内の複数プロセス間で通信を行
うための,UNIXドメインソケットという物がある. IP通信にしてもIPv4とIPv6がある. ソケットAPIは,それら すべてをほぼ同一のインタフェースで使えるように設計されている.
• このため一々,ソケットAPIの引数に「私はどの体系(IPv4, IPv6, UNIXドメインetc.)で通信がしたいです」
という事を明示的に指定する必要がある⇒余分な引数が増える.
• TCP, UDPというような, IPにのみ通用する固有名詞もAPIの表面にあからさまに現れる事はない. だから,
TCPを使って通信する時に, socket(TCP)とでも書ければまだいい物を, socket(. . . , SOCK STREAM)などと いう,間接的な物の言い方になる. ⇒引数の意味が分かりにくい.
• 通信手段が異なればアドレスの表現も違うので,ソケットのAPIには, IPアドレスを表すようなあからさまな引数 は直接現れない. 例えばIP通信では,通信の宛先は, IPアドレスとポートで指定するが, UNIXドメイン通信では, ファイルのパス名(“/tmp/foo”などの名前)で指定する. だからconnectの引数を, connect(”192.168.1.100”,
50000)とするわけには行かない. そこですべての通信手段のアドレスを包含したようなデータ型(sockaddr)が,
APIの表面には現れ,それに無理やり, IPアドレスを渡すような仕組みが用いられる. ⇒引数の渡し方が分かり にくく, C言語に習熟していない人には難解に感じられる.
• 同じ理由で, manページでsocketのAPIを見ても, IP通信をするときの固有のやり方までは書いていない. 例 えばman connectを見ても, IPアドレス192.168.1.100のポート50000につなぐ方法が書いていない.
以上の心の準備を元に, 実際のAPIを解説する.