クライアント・サーバー型システムの試作(サーバー)の続きでクライアント側のプログラムです。プロトコルや画面表示内容はサーバー側の投稿にあるので、さっそくコードを。ちなみにコンソール・アプリケーションです。
Main メソッドは、getData メソッドの呼び出しとサーバーから取得したデータの表示を行なっているだけです。
//
static void Main(string[] args)
{
var receiveData = getData();
Console.WriteLine("取得したデータ:");
Console.WriteLine(receiveData);
Console.ReadLine();
}
getData メソッドでは、サーバーへの接続、HELO コマンドによるサーバーとのコマンド処理状態への遷移、GET コマンドを実装する get メソッドの呼び出し、QUIT コマンドによるコマンド処理状態の終了そしてサーバーとの接続の切断を行います。
//
private static string getData()
{
// 文字コードを UTF-8 とする
var enc = System.Text.Encoding.UTF8;
// サーバーのホスト名とポート番号
var host = "localhost";
int port = 2001;
// TcpClient を作成し、サーバーと接続する
var tcp = new System.Net.Sockets.TcpClient(host, port);
Console.WriteLine("サーバーと接続しました。");
var rData = "";
try
{
var rStr = "";
// NetworkStream を取得する
using (var stream = tcp.GetStream())
{
// サーバーから受信
rStr = receiveData(stream, enc);
if (!rStr.StartsWith("100 "))
{
Console.WriteLine("サーバーの準備ができていません。");
return rStr;
}
sendData(stream, "HELO\r\n");
rStr = receiveData(stream, enc);
if (!rStr.StartsWith("110 "))
{
Console.WriteLine("サーバーの準備ができていません。");
return rStr;
}
rData = get(stream, enc);
sendData(stream, "QUIT\r\n");
rStr = receiveData(stream, enc);
// 閉じる
stream.Close();
}
}
catch (System.IO.IOException e)
{
if (e.InnerException.GetType() == typeof(System.Net.Sockets.SocketException) &&
(e.InnerException as System.Net.Sockets.SocketException).ErrorCode == 10053)
{
Console.WriteLine("サーバーとの接続がサーバー側のタイムアウトにより切断されました");
}
else
{
throw;
}
}
finally
{
tcp.Close();
Console.WriteLine("切断しました。");
}
return rData;
}
get メソッドでは、GET コマンドの処理を実装しています。
GET コマンドでは、サーバーからコマンドの受信と実行 OK を伝える [120 Send data\r\n] が送られ、続けてデータが送られてきます(終端は [\x1a\r\n])。
そのため、受信したデータの最初のコードが [120 ] であることを確認したのち、最初の [\r\n] までの文字列を飛ばして、[\x1a\r\n] が送られてくるまで蓄積しています。そして得られた文字列から [\x1a\r\n] を削除してデータを得ています。
//
private static string get(System.IO.Stream stream, System.Text.Encoding enc)
{
var result = "";
sendData(stream, "GET\r\n");
var rData = receiveData(stream, enc);
if (rData.StartsWith("120 "))
{
var workArea = new StringBuilder(rData.Substring(rData.IndexOf("\r\n") + 2));
if (!rData.EndsWith("\x1a\r\n"))
{
do
{
rData = receiveData(stream, enc);
workArea.Append(rData);
}
while (!rData.EndsWith("\x1a\r\n"));
}
result = workArea.Replace("\x1a\r\n", "").ToString();
}
else
{
Console.WriteLine("サーバーからエラーが通知されました。");
}
return result;
}
そして、最後は receiveData メソッドと sendData メソッドです。
こちらの receiveData メソッドは、コマンド及びデータの終端である [\r\n] が受信したデータの終わりにあったら、受信したデータを文字列に変換して返すようにしてみました。
//
private static string receiveData(System.IO.Stream stream, System.Text.Encoding enc)
{
// サーバーから送られてきたデータを受信する
var recieveMessage = "";
using (var memStream = new System.IO.MemoryStream())
{
var rBuff = new byte[50];
int rSize;
do
{
// データの一部を受信する
rSize = stream.Read(rBuff, 0, rBuff.Length);
// rSize が 0 のときにはサーバーが切断したと判断
if (rSize == 0)
{
Console.WriteLine("サーバーが切断しました。");
break;
}
// 受信したデータを蓄積する
memStream.Write(rBuff, 0, rSize);
} while (rBuff[rSize - 2] != 0x0D || rBuff[rSize - 1] != 0x0A); // 0x0D:\r, 0x0A:\n
recieveMessage = enc.GetString(memStream.ToArray());
memStream.Close();
}
Console.WriteLine("[S]" + recieveMessage);
return recieveMessage;
}
private static void sendData(System.IO.Stream stream, string str)
{
// 文字列をバイト配列へ
var data = System.Text.Encoding.UTF8.GetBytes(str);
stream.Write(data, 0, data.Length);
Console.WriteLine("[C]" + str);
}
「クライアント・サーバー型システムの試作(クライアント)」への1件のフィードバック