インターネットソフトウェア(1日目)(3-4限目) TCP/IPプログラミング演習(C言語)

【目次】


注意事項

  1. この演習は4名1組のグループ単位で行う。
  2. 課題2又は課題3については、コマンドのソースコードを作成して講師又はTAのチェックを受けること。

なお、この演習はどの環境(Linux, MacOS X, Windowsなど)で行っても構わない。また、サンプルプログラムはLinux上で標準ライブラリで動作することを確認しているが、他の環境では正しく動作しない可能性があるので、各自の環境に合わせて対応すること。

到達目標

この演習は、以下の項目に関するスキルを習得することを目標とする。

  1. ソケットAPIを用いた基本的なTCP/IPプログラミング(C言語)

1 TCP/IPの概要

TCPおよびIPは、インターネットアプリケーションにおいて最も採用されている通信プロトコルである。TCP/IPによって作られるネットワークは、さまざまなメディア(デバイス)を用いて構成される。(図1.1)

p1-1.gif
(図1.1:TCP/IPネットワーク)

IP(Internet Protocol)は、OSI参照モデルのネットワーク層にあたり、パケット(TCP/IPにおけるデータの単位)を宛先アドレスによって示された目的地まで届けるパケット転送サービスの役割を果たす。また、TCP(Transmission Control Protocol)はトランスポート層にあたり、ホスト間で信頼性のあるパケット転送サービスの役割を果たす。

OSI参照モデルのような階層化されたプロトコルスタックでは、下位層が上位層にサービスを提供することによって、ホスト間のアプリケーション通信を実現している。(図1.2)

p1-2.gif
(図1.2:プロトコルスタックの動作原理)

TCPと同じトランスポートプロトコルとしてよく利用されるものに、UDP(User Datagram Protocol)がある。UDPはシンプルなデータ通信方式であり、TCPとは異なりホスト間の通信において信頼性を提供しない。

TCPおよびUDPを使用する代表的なアプリケーションの例を示す。(図1.3)

p1-3.gif
(図1.3:TCP&UDPアプリケーション)

以下では、TCP/IPを用いたネットワーク通信について説明する。

2 パケット交換

TCP/IPにおけるパケット交換は、次のような手順で行われる。(図2.1)

p2-1.gif
(図2.1:パケット交換の流れ)

データの送り手は、まず、TCP層においてアプリケーションから受け取ったデータを一定の大きさのセグメントに分割(フラグメンテーション)する。次に、分割されたセグメントにTCPヘッダを付けてIP層に渡す。IP層では、さらにアドレス情報などが書かれたIPヘッダを付加してデータリンク層に渡す。データリンク層・物理層では、使用するメディアに応じたフレーム処理や符号化処理が行われ、電気信号として受け手へ伝送する。

データの受け手では、これらの処理が逆順に行われ、セグメントに分割されたデータを再構築(デフラグメンテーション)し、アプリケーションにデータが渡される。

以上のように、TCP/IP通信では、「データのパケット化」→「パケットの転送」→「パケットからデータ復元」というように、大きく3段階の手順によってパケット交換が行われている。

ここで、TCPの信頼性について述べる。TCPの信頼性とは、「送り手が送信したデータが、そのままの順序で正しく受け手に届く」ということである。この信頼性は、(1)順序制御、(2)再送制御、(3)ウィンドウ制御、(4)フロー制御の4つの仕組みによって実現されている。

まず、(1)順序制御では、送り手はアプリケーションから受け取ったデータをセグメントに分割し、受け手へ送信する。受け手はヘッダに示されたシーケンス番号によってセグメントの順序を確認し、正しくデータを再構築(デフラグメンテーション)する。次に、(2)再送制御では、受け手ではセグメントを受け取るごとに送り手へ確認応答(ack)を送る。これによって、全てのセグメントが送り手に届いたことが確認され、送り手は確認応答(ack)が無かったセグメントを再送する。(3)ウィンドウ制御では、「1つ1つのセグメントに確認応答していては、通信速度が悪化する」という問題を軽減するため、全てのセグメントに対する確認応答(ack)を待たずに、ウィンドウ値で指定された分だけ複数のセグメントを同時に送信する。最後に、(4)フロー制御では、受け手の負荷状況(受信バッファの状態)に応じて、受け手は許容可能なセグメント量を確認応答(ack)を使って送り手に通知し、送り手は受け手の許容可能なセグメント量に応じたウィンドウ値でセグメントを送信する。

以上のような仕組みによって、TCPは信頼性のある通信を実現している。一方、UDPでは、このような仕組みは無く、送り手は一方的に受け手へデータを送りつける。このため、UDPでは上位層で信頼性を確保するための仕組みが必要となる(ただし、UDPは仕組みがシンプルであるため、TCPに比べて軽量で高速なプロトコルである)。

3 IPアドレスとポート番号

TCP/IP通信において、データを転送する宛先のホストを指定する場合、終点を意味するアドレスが使用される。このアドレスは、アプリケーション層では通常はドメインネーム(例: ie.u-ryukyu.ac.jp)で表されるが、TCP/IP通信では、IP層によってドメインネームがIPアドレスに変換され、IPアドレスによって終点ホストが判断される。

IPアドレスは、通常はドット(".")区切りの10進表記というバイト単位の形式で表現しする(例:133.13.48.30)。IPアドレスの長さは4バイトであり、アプリケーションは、下図にあるようにアドレスの第1バイトを見ればネットワークの中で使用できるユニークなIPアドレスの数を知ることができる。これによって、どのビットがネットワークアドレスビットで、どのビットがローカルに管理されているホストアドレスビットかを知ることができる。

IPアドレス(ここでは、IPv4:Internet Protocol version 4を指す)には4つのクラス(A,B,C,D)(図3.1〜3.4)がある。1つのネットワーク上の個々のシステムのインターフェースは、ローカルに管理されているホストアドレスによって識別される。また、ネットワークによってはさらに管理しやすい管理区分を設けるため、ホストアドレスビットを用いてサブネットを作る場合もある。

p3-1.gif
(図3.1:クラスA)
p3-2.gif
(図3.2:クラスB)
p3-3.gif
(図3.3:クラスC)
p3-4.gif
(図3.4:クラスD)

この他に、ループバックアドレス(127.0.0.0〜127.255.255.255,うち127.0.0.1はローカルホストアドレス)や、ブロードキャストアドレス、マルチキャストアドレス(=クラスDアドレス)、プライベートアドレス(クラスA:10.0.0.0〜10.255.255.255,クラスB:172.16.0.0〜172.31.255.255,クラスC:192.168.0.0〜192.168.255.255)などが決められている。

なお、上記のようなアドレス体系は、一般にクラスフルと呼ばれており、アドレスの効率使用の面で問題がある。さらに、IPv4アドレスは近年の世界的なインターネットの普及によって枯渇が懸念されており、CIDR(Classless Inter-Domain Routing)によるクラスレス化やNAT(Network Address Translation)による一時的な延命が図られているほか、IPv6(Internet Protocol version 6)への移行が急がれている。

IPアドレスは、ネットワーク上に存在するホストを識別するものである。これに対して、ホスト上で動作しているアプリケーションを識別するのに用いるのがポート番号である。ポート番号は、トランスポート層(TCP,UDP)における識別子であり、16ビットの整数値(0〜65535)で表す。

16ビットのポート番号は、次の3種類に分類されている。(表3.1)

0〜1023ウェルノウンポート(システムポート)
1024〜49151予約済みポート(ユーザーポート)
49152〜65535ダイナミックに割り当てられるor私的に利用されるポート
(表3.1:ポート番号の分類)

0〜1023はシステムポートとも呼ばれ、自ホストのポート番号に指定するためにはroot権限が必要である。また、1024〜49151はユーザーポートとも呼ばれ、一般のアプリケーションから利用される。さらに、49152〜65535はTCP/IP通信における戻り通信用にダイナミックに割り当てられる。なお、TCPとUDPでポート番号は独立である。

4 ソケット

TCP/IP通信におけるプロトコルスタックは、個々の層をつなぐインターフェースによって実現される。このうち、アプリケーションとトランスポート層(TCP,UDP)の間には、ソケットと呼ばれるインターフェースが存在し、ユーザーはこのソケットを利用することによって、アプリケーションからトランスポートサービスを利用することができる。

ソケットにはタイプと呼ばれる概念がある。TCPにおけるタイプとはストリームであり、UDPにおけるタイプとはデータグラムである。先に述べたように、TCPは信頼性が高く、送受信のデータ順序が保証されており、双方向である。一方、UDPは信頼性は低いが即時性が高く、送受信のデータ順序が保証されていない。

ソケットを使ったプログラムを組む場合、下の図ようなシステムコールが使われる。(図4.1)

p4-1.gif
(図4.1:ソケットプログラミングの基本構造)

図4.1の左側を一般にクライアントと言い、右側をサーバーと言う。TCP/IPとソケットを使って通信プログラムを組むということは、クライアント・サーバープログラムを組むということに他ならない。

5 クライアント・サーバーモデル

ここでは、クライアント・サーバー通信の実験として、WWWサーバーへのアクセスをモデルに、クライアントからtelnetコマンドを使ってWWWサーバーにアクセスし、任意のページデータを取得してみる。

WWWサーバーとクライアントの間では、HTTP(Hyper Text Transfer Protocol)と呼ばれるプロトコルによってデータの転送が行われている。SafariやFirefox、Lynxなどのブラウザー(クライアントプログラム)は、WWWサーバーとの間にTCP/IPによる通信路をオープンし、その上でHTTPプロトコルによって必要なデータを得るための命令(リクエスト)をWWWサーバーに送り、WWWサーバーはその命令にもとづいてクライアントにデータを返答(レスポンス)している。

HTTPで定義されている命令の例を表5.1に示す。 なお、HTTPの命令はRFC2616,9.2〜9.8で規定されている。

GET情報を得る(ヘッダと本体の両方)
HEAD情報のヘッダのみを得る
POST新しく情報を作る
PUT情報の保存
DELETE情報の削除
TRACEループバックのテスト
(表5.1:HTTP命令)

HTTPで定義されている状態コードの例を表5.2に示す。 なお、HTTPの状態コードはRFC2616,6.1で規定されている。

200OK(エラーなし)
301要求されたデータが移動した
400要求の形式にエラーがある
404要求されたデータが見つからない
(表5.2:HTTP状態コード)

ここで、telnetコマンドを使ってWWWサーバーにアクセスするには、

> telnet (サーバーアドレス) (ポート番号)

というようにすれば良い。
通常、WWWサーバーは80番ポートで動作しているので、例えば、情報工学科のWWWサーバーにtelnetアクセスするには、

> telnet ie.u-ryukyu.ac.jp 80

とすれば良い。
telnet接続をしたら、HTTPプロトコルに従ってコマンド入力することで、WWWサーバーに命令を送ることができる。
例えば、

> GET /index-e.html HTTP/1.0

とすることによって、指定したページデータを取得することができる。

以上のように、telnetを使うことによって、クライアントからWWWサーバーにサクセスし、HTTPプロトコルの命令にもとづくレスポンスを得ることができる。また、telnetはWWWサーバーに限らず、SMTPサーバー(25番ポート)やPOP3サーバー(110番ポート)、NNTPサーバー(119番ポート)(いずれもTCPポート)など(これらは、ASCII文字列型プロトコルという)でも同様に、それぞれのプロトコルにもとづいた操作が可能である。つまり、telnetはサーバーとクライアントの間にプロトコルごとの通信路をオープンして、その中で通信を交換(つまり、ASCII文字列を使ってリクエストとレスポンスを交換)していると言える。

6 クライアント・サーバープログラム

5章では、telnetコマンドを使ってWWWサーバーにアクセスし、WWWサーバーへ命令を送ってページデータを取得した。ここでは、ソケットプログラムによって同じことを実現するためのプログラミング方法を理解する。

TCPを使ったクライアント・サーバープログラムは、次のような流れで実装する。

[クライアント側]
- ソケットを作成してサーバーに接続する
- サーバーにリクエストを送信する
- リクエストしたデータをサーバーから受信する
[サーバー側]
- ソケットを作成してコネクションを待つ
- クライアントからのコネクションを受けてリクエストを処理する
[クライアント側&サーバー側]
- 処理が完了したらクライアント・サーバー両方でコネクションを閉じる

上記の動作を理解するため、サンプルプログラムを用意した。このサンプルプログラムはサーバー(server.c)を起動することで、サーバーはクライアント(client.c)の標準入力から入力された文字列を自身の標準出力に表示し、同じ文字列をクライアントに返すというものである(=TCP通信を使ったエコープログラムである)。

■課題1:サンプルプログラムの実行
サンプルプログラムを自分の実験環境で実行せよ。

7 クライアントコマンドの作成

5章では、telnetコマンドを使ってWWWサーバーにアクセスし、WWWサーバーへ命令を送ってページデータを取得した。ここでは、ソケットプログラムによって同じことを実現する。

6章のサンプルプログラム(特にクライアントプログラム(client.c))を参考にして、以下の課題を行うこと。

■課題2:HTTPクライアントの作成 *過去に実験IIで同テーマを受講済みの場合は除く。

ソケットおよびHTTPプロトコルを使って、任意のWWWサーバーから任意のURLのページを取得し、標準出力に表示するコマンドプログラムを作成せよ。

[実行例]
> httpget ie.u-ryukyu.ac.jp/index-e.html
(以下、該当ページのhtmlソースが表示される)

以下に、ソースコードを作成する上での注意事項を示す。

  1. C言語で作成すること。
  2. makeコマンドを使ってコンパイルできるようにMakefileを付けること。

以下に、実現すべきコマンドの機能を示す。

  1. 改行1回でコマンド実行できるようにする。
  2. ポート番号(tcp:80)を指定しないでもコマンド実行できるようにする。
  3. http://ie.u-ryukyu.ac.jp/ のように、jp や / で終わるアドレス指定でもコマンド実行(htmlソース取得)できるようにする。

■課題3:SMTPクライアントの作成 *過去に実験IIで同テーマを受講済みの場合。

ソケットおよびSMTPプロトコルを使って、SMTPサーバーを使ってメールを送信するメールクライアントコマンドをせよ。

以下に、実現すべきコマンドの機能を示す。

  1. メールの宛先(To:行)だけではなく、送信元(From:行)も付加すること。
  2. 任意のメールタイトル(Subject:行)、同本文を送信できること。
  3. 上記は日本語に対応していなくてもよい。また、本文は1行のみ対応でもよい。

使用するメールサーバー:
n-lab.info

テストメール送信先アドレス:
is2017-test@n-lab.info

テストメール送信元アドレス:
(各自の学科メールアドレス) 例:e165700@ie.u-ryukyu.ac.jp

8 おわりに

この演習では、C言語によるTCP/IPを使った基本的なクライアントプログラミングを行った。なお、TCPが提供する機能(信頼性など)を重視しないのであれば、UDPを使うことでもデータを宛先ホストに届けることができる。個々のアプリケーションが求める性能や品質によって、トランスポートプロトコルを選択することが重要である。また、大規模なリクエスト処理に対応する性能を得るためには、マルチプロセスやマルチスレッドプログラミングが必要になる。さらに、すでに普及が始まっているIPv6に対応したIPv4/IPv6デュアルスタックプログラミングを行うことも必要である。

7 参考

[ Back ]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-08-22 (火) 07:18:45 (362d)