しかし、中には既に古いプロトコルとなってしまい、現在ではサービスがなかなか提供されていないものもあります (Echo サーバや DateTime サーバ等)。
しかし、これらのサンプルは非常にシンプルであり、コンポーネントの動作を理解するにはお手軽で便利なものとなっています。(サーバがあれば、ですが。)
そこで、弊社の UDPPort および IPDaemonを使って非常にシンプルな UDP Echo サーバおよび DateTime サーバを C# 作成してみました。(サービス仕様の詳細に興味のある方は、RFC862 - Echo Protocol および RFC867 - Daytime Protocol をご参照ください。)
●UDPEcho サーバ
この UDP Echo サーバの UI は非常にシンプルです。ListView が1つと Button が1つだけです。VisualStudio でフォームを作成し、これらをドロップします。名前はそれぞれ既定値の ListView1 および button1 です。続いて UDPPort をフォームにドロップします。こちらも名前は規定値の udpport1 です。この状態で、以下のようなソースを作成します。(VS2005 の場合。) ユーザが定義するのは、ボタンクリックイベントハンドラ button1_Click と、UDPPort の DataIn イベントハンドラ udpport1_OnDataIn のみです。
namespace UDPEchoServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.Equals("&Start"))
{
udpport1.Active = false;
udpport1.InvokeThrough = this;
udpport1.LocalPort = 7; // UDP Echo
udpport1.Active = true;
udpport1.AcceptData = true;
button1.Text = "&Stop";
}
else
{
udpport1.Active = false;
button1.Text = "&Start";
}
}
private void udpport1_OnDataIn(object sender, nsoftware.IPWorks.UdpportDataInEventArgs e)
{
ListViewItem newdata = new ListViewItem(new String[] {DateTime.Now.ToString(), e.SourceAddress, e.Datagram});
listView1.Items.Add(newdata);
udpport1.RemoteHost = e.SourceAddress;
udpport1.RemotePort = e.SourcePort;
udpport1.Send(e.DatagramB);
}
}
}
非常にシンプルですね。button1_Click では、サーバ停止状態 (button1.Text が "&Start") であれば、使用するポートを設定し、udpport コンポーネントをアクティブにし、データを受け入れ可能にします。サーバ動作中であれば、サーバを非アクティブにします。動作中にデータを受信すると、udpport1_OnDataIn イベントハンドラが実行されます。ここでは受信したデータグラムの情報をリストビューに表示し、受信したデータをそのまま送信元に返送しています。次は少し複雑な DayTime サーバを見てみましょう。
●DayTime サーバ
こちらの DayTime サーバは、UDP/IP と TCP/IP を両方サポートする関係上 UI も少し項目が増えています。情報表示用のリストビュー、プロトコル選択用チェックボックス (UDP TIME と TCP TIME)、返す日時フォーマット選択用のラジオボタン (US 形式か UK 形式か)、そして起動/停止用のボタンです。これらをフォームのドロップした後、UDPPort コンポーネントおよび IPDaemon コンポーネントをフォームにドロップします。今回もユーザが作成しなければならないのは、起動/停止ボタンのクリックイベントハンドラ、UDPPort の OnDataIn イベントハンドラ、および IPDaemon の OnDataIn イベントハンドラのみです。
namespace DayTimeServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void bStart_Click(object sender, EventArgs e)
{
Control[] controls = { chkbUDP, chkbTCP, rbUK, rbUS };
if (bStart.Text.Equals("&Start"))
{
foreach (Control c in controls)
{
c.Enabled = false;
}
if (chkbUDP.Checked)
{
udpport1.Active = false;
udpport1.InvokeThrough = this;
udpport1.LocalPort = 13; // UDP Daytime port
udpport1.Active = true;
udpport1.AcceptData = true;
}
if (chkbTCP.Checked)
{
ipdaemon1.InvokeThrough = this;
ipdaemon1.LocalPort = 13; // TCP Daytime port
ipdaemon1.Listening = true;
}
bStart.Text = "&Stop";
}
else
{
if (chkbUDP.Checked)
{
udpport1.AcceptData = false;
}
if (chkbTCP.Checked)
{
ipdaemon1.Listening = false;
}
foreach (Control c in controls)
{
c.Enabled = true;
}
bStart.Text = "&Start";
}
}
private void udpport1_OnDataIn(object sender, nsoftware.IPWorks.UdpportDataInEventArgs e)
{
DateTime now = DateTime.Now;
ListViewItem newdata = new ListViewItem(new string[] {
now.ToString(), e.SourceAddress, "UDP"
});
listView1.Items.Add(newdata);
String fmt = rbUK.Checked ? "dd MMM yy hh:mm:ss' UTC'" : "dddd', 'MMMM dd', 'yyyy hh':'mm':'ss'-UTC'";
String utcnow = now.ToUniversalTime().ToString(fmt);
udpport1.RemoteHost = e.SourceAddress;
udpport1.RemotePort = e.SourcePort;
udpport1.Send(System.Text.Encoding.UTF8.GetBytes(utcnow+"\r\n"));
}
private void ipdaemon1_OnDataIn(object sender, nsoftware.IPWorks.IpdaemonDataInEventArgs e)
{
DateTime now = DateTime.Now;
ListViewItem newdata = new ListViewItem(new string[] {
now.ToString(), ipdaemon1.Connections[e.ConnectionId].RemoteHost, "TCP"
});
listView1.Items.Add(newdata);
String fmt = rbUK.Checked ? "dd MMM yy hh:mm:ss' UTC'" : "dddd', 'MMMM dd', 'yyyy hh':'mm':'ss'-UTC'";
String utcnow = now.ToUniversalTime().ToString(fmt);
ipdaemon1.Send(e.ConnectionId, System.Text.Encoding.UTF8.GetBytes(utcnow+"\r\n"));
ipdaemon1.Connections[e.ConnectionId].AcceptData = false;
ipdaemon1.Connections[e.ConnectionId].Connected = false;
}
}
}
bStart_Click はサーバの起動と停止を制御します。起動時にはチェックボックスやラジオボタンを無効化して動作中に変更できなくし、またプロトコル選択チェックボックスの状態に応じて UDPPort コンポーネントおよび IPDaemon コンポーネントのインスタンスをアクティブ化します。停止時にはプロトコルの選択状態に応じて対応するコンポーネントを非アクティブ化し、チェックボックスおよびラジオボタンを有効にします。udpport1_OnDataIn では UDP で受信したデータから得られた送信元に対し、現在時刻を指定されたフォーマットで UDP で返信します。同様に ipdaemon1_OnDataIn では TCP で受信したデータから得られた送信元に対し現在時刻を指定されたフォーマットで TCP で返信します。なお、この DateTime サーバでは、日時は UTC で返すようにしています。
このどちらのサーバも、弊社のデモに対するテスト用サーバとしてご利用いただけます。