DAYTIMEサーバー
 DAYTIME (RFC 867) はホストの日時を文字列でクライアントに通知するサービスです。 ここでは C# を用いて DAYTIME サーバーを作ってみます。今回は簡単に作るために並行処理 (スレッド)は行いません。複数同時アクセスがあった場合は後から来た要求には待ってもらいます。 通信には TCP を用います。ポートはDAYTIMEのウェルノウンポート 13 を使います。DAYTIME では 形式は特に決まっていませんが、今回は「2003/02/01 15:58:18」という形式で通知します。


プログラミング
 まずは使う名前空間を using します。

名前空間のエイリアスを作成
using System;
using System.Net.Sockets;


 System 名前空間は「Hello World」プログラムのところで説明したとおり、基本的な型の ルート名前空間です。System.Net.Sockets 名前空間は Winsock インターフェイスのマネージ実装、 簡単に言うとソケットを使う機能を提供します。今回はこの名前空間の中で「TCPListener」 「Socket」の2つのクラスを使います。

TCPListener の用意

class Daytime {
  public static void Main() {
    TcpListener serv;
    try {
      serv = new TcpListener(13);
      serv.Start();
      Console.WriteLine("DAYTIME Server Started.");
    } catch (Exception e) {
      Console.WriteLine(e.ToString());
      return;
    }


 クラス「Daytime」を作り、エントリポイント (public static void main) を作ります。 その中でまず TCPListener クラス「serv」を定義します。TCPListener クラスは TCP クライアント からの接続を待機します。次に例外処理「try 〜 catch」でくくり、serv による待ち受けを開始 します。ここではポート 13 を TCPListener のコンストラクタに渡し、インスタンスを作っています。 Start メソッドで待ち受けを開始し、その旨を「Console.WriteLine」で標準出力(ディスプレイ)に 出力します。TCPListener のインスタンスの作成、待ち受け開始に失敗した場合は、catch により 拾われたエラーを出力してアプリケーションを終了 (return) します。Exception クラスはエラーを 表すクラスで、ToString メソッドでエラーを文字列化させています。

日時を返す処理

    Console.WriteLine("Press ^C to Stop.");

    while (true) {
      Socket s = serv.AcceptSocket();
      if (s.Connected) {
        String d = DateTime.Now.ToString();
        Byte[] bs = new Byte[d.Length];
        bs = System.Text.Encoding.ASCII.GetBytes(d);
        try {
          s.Send(bs, bs.Length, 0);
          s.Close();
          Console.WriteLine("Send {0}", d);
        } catch (Exception e) {
          Console.WriteLine(e.ToString());
        }
      }
    }


 while(true) で無限ループに入ります。そのため、終了させるには [Ctrl] + [C] を入力する必要 があります。まずはその旨を「Console.WriteLine」で出力します。次に無限ループに入ります。

 serv の AcceptSocket メソッドで保留中の接続要求を受け入れます。接続要求があるまではこの位置 で処理は停止しています。接続要求を受け入れると、ScceptSocket メソッドはデータ送受信用の ソケットを返してくるので、そのソケットを Socket クラス「s」に取り込みます。

 s の Connected プロパティで接続されていることを確認したら、送信する日時の文字列を作ります。 DateTime 構造体は Now プロパティをもちます。Now はコンピュータのローカルな日付と時刻を取得 します。これを ToString メソッドで文字列にし、String d に格納します。

 次に d を送信するためにバイト配列に変換します。まず d.length(文字列 d の長さ)の Byte 配列「bs」を作り、bs にバイト配列に変換した d を入れます。「System.Text.Encoding.ASCII. GetBytes(d)」でバイト配列は取得できます。

 例外処理で送信処理をくくっておき、s の Send メソッドでバイト配列 bs を送信します。送信 したらソケットを閉じ、「Console.WriteLine」で送信した日時と同じものを表示します。 WriteLine メソッドの中身に {0} とありますが、こうすることでさらに与える引数(ここでは d ) をこの部分に入れることができます。内容的には「Console.WriteLine("Send " + d);」と同じです。 なお、例外処理の catch は TCPListener クラスのところと同じです。

 これで処理を終えて、また接続要求の待機に戻ります。 プログラムの全文を示しておきます。

DAYTIMEサーバー
using System;
using System.Net.Sockets;

class Daytime {
  public static void Main() {
    TcpListener serv;
    try {
      serv = new TcpListener(13);
      serv.Start();
      Console.WriteLine("DAYTIME Server Started.");
    } catch (Exception e) {
      Console.WriteLine(e.ToString());
      return;
    }

    Console.WriteLine("Press ^C to Stop.");

    while (true) {
      Socket s = serv.AcceptSocket();
      if (s.Connected) {
        String d = DateTime.Now.ToString();
        Byte[] bs = new Byte[d.Length];
        bs = System.Text.Encoding.ASCII.GetBytes(d);
        try {
          s.Send(bs, bs.Length, 0);
          s.Close();
          Console.WriteLine("Send {0}", d);
        } catch (Exception e) {
          Console.WriteLine(e.ToString());
        }
      }
    }
  }
}



動かしてみる
 ソースコードをコンパイルし、まずはサーバーを起動します。そして telnet でサーバーに 接続してみます。Windows2000, XP の場合はコマンドプロンプトを起動して次のように入力します。

telnet 127.0.0.1 13

 そして Enter キーを押すとサーバーから日時が返されます。

2003/02/01 17:00:18

ホストとの接続が切断されました。


 サーバーの画面はこんな感じになります。

DAYTIME Server Started.
Press ^C to Stop.
Send 2003/02/01 17:00:18
Send 2003/02/01 17:00:50


 このような感じで簡単(?)にサーバープログラムが書けました。