コネクション型通信プログラム

以降では、TCPを利用した通信プログラムの作成方法を説明していきます。

コネクション型通信であるTCPは、コンピュータ間に仮想的な通信路を作って 通信をします。この仮想的な通信路は水道管のようなものであり、入口から流 し込んだ順番に出口から出てきます。つまり、データは送信した順番で受信さ れますし、通信失敗時には再送信などが自動的に行われます。従って、WWWや メールなどの多くのインターネット上の通信は、このTCPにより実現されてお り、インターネットの通信の基礎となる通信方法であるといえます。

TCPを利用した通信では前述のソケットを利用します。ソケットは、ファイル の出力・入力プログラムと同じやり方でコンピュータ間のデータの送信・受信 プログラムを書けるようするものです。ただし、ソケットを使うためには、ま ず準備作業として(1)ソケットの生成と、(2)そのソケットを通信相手のソケッ ト接続を行う必要があります。その準備作業を経て初めて、(3)ソケットを介 してデータをやり取りが行えるようになります。そして、通信終了後には(4) ソケット間の接続を断つという作業が必要となります。

TCP通信を利用したプログラムではほぼ同じ準備作業を行います。複雑な構造 体を利用するなど、C言語の初心者には難しい部分もありますが、一度その方 法を知ってしまえば別のTCP通信を利用したプログラムでも再利用できます。 また、本書では、この準備作業の部分と、実際の通信過程を分けてプログラム を構成します。このため、準備作業の中身が理解できていなくても、通信プロ グラムは書けるに解説していきます。

TCPなどのコネクション型通信は電話を思い浮かべると簡単に理解できます。 電話による会話では、電話をかける側と電話がかかってくるのを待っている側 に役割が分かれます。これと同じように、コネクション型通信もソケットによ る通信接続をする方(クライアントと呼びます)と、通信接続を待っ ている方(サーバと呼びます)の二つに役割が別れています。また、 それぞれ準備作業にも違います。しかし、一度接続されればクライアントとサー バの区別はなく、電話と同じように両方が同時にデータの送り手にも受け手に もなれます。

コラム:クライアント/サーバ

「クライアント/サーバ」という言葉は様々な意味で利用されることが多く 誤解を生じさせます。例えば、

ソケットはオペレーティングシステムに管理されています。従って、プログラ ムだけでは作ることも接続することもできず、オペレーティングシステムの助 けが必要になります。オペレーティングシステムに処理をお願いする方法、 つまり、システムコールやAPI(Application Program Interface)を使って ソケットの生成及び接続を行うことになります。

コラム:システムコールとAPI

UNIXやWindows、MacOSという近代的なOSでは、ファイルの読み書き、キーボー ドから入力受付、画面への出力、ソケット通信などの入出力機械を一般のプロ グラムが直接行うことは禁止されています。こうした入出力機械はオペレーティ ングシステムによって管理されています。プログラムがこれらを利用するとき にはオペレーティングシステムに依頼する必要があります。そして、その依頼 の窓口になるのが、オペレーティングシステムにより提供されるシステムコー ルやAPI(Application Program Interface)です。

なお、システムコールは主にUNIXでよく使われる名称、一方、APIはWindowsや MacOSで使われる名称です。両者の違いははっきりしませんが、APIには、オペ レーティングシステムへの処理依頼だけでなく、プログラム作成に便利な関数 や機能なども含まれていることが多いです。また、WindowsやMacOSでは描画や ウィンドウ操作などもAPIを使って実現します。従って、APIをたくさん知って いるプログラマーが優秀なプログラマーの条件の一つになりつつあります。た だし、Windowsなどでは何千ものAPIがあります。システムコールやAPIは関数 と同じ要領で一般のプログラムからも呼び出すことができるようになっていま す。

ところで、今までのプログラムをたくさん書いてきたけど、システムコールや APIというものを使ったことがないという方も多いでしょう。例えばC言語であ ればprint()という関数で画面に出力できます。これは、システムコー ルやAPIそのものを使う代わりに、システムコールやAPIを内部で使っている関 数を使っていたからです。printf()もその内部でシステムコールや APIを使っているのです。(コラム終わり)

TCPを利用するプログラムでは以下のシステムコールを使います。他にも幾つ かのシステムコールには数多くあるのですが、一般的なプログラムに関しては 以下のものを組み合わせれば十分です。

TCP通信に利用するシステムコール(クライアント側)
socket()ソケット生成
connect()ソケット接続
read()データ受信
write()データ送信
close()ソケット消去

TCP通信に利用するシステムコール(サーバ側)
socket()ソケット生成
bind()ソケット登録
listen()ソケット接続準備
accept()ソケット接続待機
read()データ受信
write()データ送信
close()ソケット消去

上記のうちで、read()write()close() システムコールはファイル入出力プログラムで利用された方も多いでしょう。

TCP通信は大きく分けて3つの段階に割れます。一つ目はサーバとクライアン トプログラムそれぞれがソケットを作り、両ソケットの間に通信接続を確立す ることです。二番目は両者のあいだのデータの送受信、三番目は通信接続を切 断することです。

通信を開始する前に、クライアントもサーバもまずソケットを生成します。し かし、クライアントを電話をかける側、一方のサーバ側は電話がかかってくる のを待っている側ですので、サーバ側はライアントからの通信接続要求をまつ 状態になります。一方、クライアント側はサーバ側に通信接続要求を送ります。 その結果、サーバのソケットとクライアントのソケットのあいだに通信接続を 確立するようになり、いよいよデータの送受信が始められるようになります。 一度、通信接続が確立すると、基本的に両者に違いはありません。ソケットに データを書き込むと、相手のソケットからそのデータを読み出すことができま す。そして、通信が終了したら、ソケット間の通信接続を切断します。

上記のシステムコールのうちsocket()はソケット生成を行います。 サーバ側はソケットを接続待機状態にする必要があり、そのために bind()listen()accept()の3つのシステム コールを利用します。ここでbind()はソケットのポート番号や通信 方式を登録します。また、listen()は通信接続待機をするのに必要 な準備を行います。そして、accept()は通信接続要求を待つシステ ムコールです。一方、 クライアント側はsocket()によりソケットを生成後は、 connect()によってサーバに接続要求を送るだけです。

接続語はそれぞれのソケットに対してwrite()システムコールを通じ てソケットにデータを書き込むと、そのデータが届きます。そこで、もう一方 はread()システムコールを通じて、ソケットを読み出すと、相手側 が送信したデータを受信することができます。通常のTCP通信プログラムでは、 通信が完了するまでwrite()read()システムコールにより データの送受信を互いに繰り返します。

そして、クライアントとサーバのどちらか一方がclose() システムコールを実行して、通信接続を切断すると通信が完了します。

コラム:全2重通信

(コラム終わり)

コラム:WinSock

TCP/IPはUNIXを中心にして発展しました。このため、TCP/IPを利用したプログ ラムにはUNIXのシステムコールが必要となります。一方、WindowsのAPIはUNIX のシステムコールとは大きく異なります。しかし、WindowsにはUNIXのソケッ ト用システムコールと互換性をもったWinSockというソケット通信用の APIが用意されています。WinSockを使えばUNIXのソケット通信プログラムが Windowsでも利用できます。ただし、WinSockは一部のシステムコールが用意さ れておらず、動作が違うものもあります。例えば、データの送受信に利用する write()read()に違いがある。また、通信終了時に利用 するclose()システムコールがWinSockにはなく、closesocket() というAPIを利用する必要があります。(コラム終わり)