特集

.NETネットワーク・プログラミング入門

高木 健一
http://www.woodensoldier.info/
2004/12/18
Page1 Page2 Page3 Page4

3.2. 簡易ファイル交換ソフトの仕組み

 まずはファイル交換の仕組みを見てみよう。

簡易ファイル交換プログラムの仕組み

 今回は上の図のような流れで作成してみる。クライアントとサーバが通信を確立した後、どちらからでも送信、受信ができるようにする。従って、ここではクライアントやサーバという言葉を使わずにファイル送信側、ファイル受信側という言葉を用いて説明する。

 データ送信側は、まず、指定されたファイルをディスクから読み込む。ファイルがテキストかバイナリかは考慮せず、すべてバイナリとして読み込むことにする。そして、読み込んだ内容を今回は送信しやすいようにBase64でエンコーディングする。Base64エンコーディングを行うと、バイナリ・データをテキスト・データに変換することができる。今回はファイル名と一緒にファイルの内容を送りたいためにこのような作りにしている。Base64エンコーディングは単純計算で33%ほどデータ量が増えるが、ファイル名とファイルの内容を連結し、1つにまとめて送信することで、プログラムは単純になる。.NET FrameworkにはBase64のエンコードデコードを行うクラスが標準で用意されている。

 送信用データとしてBase64形式でエンコードしたファイルの中身にファイル名を付加する。このときの形式を以下のように定める。

ファイル交換のための交換データ仕様
ファイルを交換するための交換用データの仕様をこのように設計する。

 この仕様では、「?」文字を、ファイル名と実際のファイルの内容の境界を表す記号として用いる。このセパレータはどのような文字でもよいが、ファイル名とBase64形式の結果に現れない文字である必要がある。こうしてできた送信用の文字列を送信する。受信側は受け取った文字列を解析していくことになる。

 データ受信側では、まず受け取った文字列から「?」を探し、ファイル名とファイルの中身の部分に分割する。ファイル名はこれで取得できるが、ファイルの中身はBase64形式でエンコードされているため、これを元のバイナリ・データに戻さなくてはいけない。そこでBase64デコーディングを行う。これで、ファイル名とファイルの中身を取得することができる。最後に受信したファイル名で受信したファイルの中身をバイナリ・ファイルとしてディスクに書き込む。

 以上が今回作成するファイル交換プログラムの処理手順である。それでは、実際にコードを見ていくことにしよう。

3.3. サンプル・プログラムの解説

 それでは、いま解説したファイル交換の仕組みについて、実際に作成したプログラムのソース・コード(C#)を見ながら、その手順を解説しよう。全ソース・コードは次のリンクからダウンロードできる。zip形式で圧縮されているので、解凍してみてほしい。なお、1台のコンピュータでもプログラムを2つ起動すれば、ファイル交換のテストは可能である。

■ポート番号の設定

 プログラムでは、まず、ポート番号の宣言を次のように記述している。

// ポート番号は9999に設定
private Int32 port = 9999;
ポート番号の設定

 このプログラムでは、ポート番号として9999番を固定的に利用している。通常は問題ないはずだが、すでにこのポート番号がほかのアプリケーションで使用されている場合には、ポート番号を変更する必要がある。また、通信を行う2つのコンピュータ間にファイアウォールが存在する場合には、ここで指定したポート番号の通信を許可するように、ファイアウォールの設定を追加する必要がある。

■サーバ側(ファイル受信側)における通信の確立

 次にソケットによる通信について、まずはサーバ側(ファイル受信側)の動作から見てみよう。次のコードはサーバを立ち上げている部分である。

// TcpListenerオブジェクトを使用してサーバを指定のポートで確立
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
TcpListenerオブジェクトによる接続の待機

 TcpListenerオブジェクトをそのコンストラクタのパラメータにIPAddress.Anyとポート番号を指定して作成している。このIPAddress.AnyとはどのようなIPアドレスでも接続を受け付けるという意味の定数である。そして、Startメソッドを呼び出すことにより、クライアントから接続されるのを待ち続ける。

 クライアントからの接続があると、TcpListenerオブジェクトはその接続要求をキューに入れておく。そのキューから接続要求を取り出して処理をするのが次のコードである。

// クライアントの要求があったら、接続を確立する
TcpClient server = listener.AcceptTcpClient();
クライアントからの接続要求の受け入れ

 TcpListenerオブジェクトのAcceptTcpClientメソッドでは、クライアントからの接続要求を受け入れて、クライアントに対する接続を確立する。このとき返されるTcpClientオブジェクト(この例では変数server)が、この接続を管理するオブジェクトになる。以後はこのオブジェクトを使用してクライアントとの通信を行う。

 データの送受信には、.NETで用意されているストリームを使う。

// クライアントとの間の通信に使うストリームを取得
NetworkStream ns = server.GetStream();
serverReader = new StreamReader(ns, Encoding.UTF8);
serverWriter = new StreamWriter(ns, Encoding.UTF8);
ネットワーク・ストリームの取得とStreamReaderオブジェクト/StreamWriterオブジェクトのセット

 確立した通信に対応するストリームを取得するには、接続を管理しているTcpClientオブジェクト(この例では変数server)のGetStreamメソッドを呼び出す。戻り値はNetworkStream型のオブジェクトである。ここで取得したストリームに対して、ReaderクラスとWriterクラスを指定する。今回は文字列をやりとりするので、指定したストリームに対応したStreamReaderオブジェクトとStreamWriterオブジェクトをそれぞれ作成する。このとき多言語の文字列(今回の設計ではファイル名)を扱えるように、エンコーディングは一般的なUTF-8に設定しておく。

 一方、受信については、受信がないかを常にチェックして、受信があれば処理できるようにループにより待機しておく。具体的には次のようなコードを記述する。

// クライアントからのデータ送信をループで待機
// いつデータ送信がきても受信するように
while (true)
{
  ProcessMessage(serverReader);
}
データの受信待ちループ

 この例では、独自に追加したProcessMessageメソッドを通じて先ほど作成したStreamReaderオブジェクトの変数serverReaderをチェックする。このProcessMessageメソッドはもし受信データがあればそれを処理し、なければ待機するという動作をする(詳細後述)。

 ダウンロードしたサンプル・プログラムのコードを詳しく見ていただければ分かると思うが、このループはアプリケーションとは別スレッドで動くようになっている。これはこのループ内の受信待機の処理がアプリケーションの動作を妨げないようにするためである。

 これでサーバ側のデータ通信の準備は完了である。次はクライアント側を見ていこう。


 INDEX
  [特集] .NETネットワーク・プログラミング入門
    1.ネットワーク・プログラミングの概要
    2..NETにおけるソケット通信の技術
  3.簡易ファイル交換プログラムの仕組み
    4..NETにおけるTCP/IP通信処理の実装
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間