SQLの窓

2013年09月12日


Framework4.5(C#) のコンソールアプリケーションで、とても簡単に HTTP サーバーを作成できます

SkyDrive へ移動

※ VS2012 用

スレッドを使ってサーバー部分を常駐しますので、プログラムにはコンソールとブラウザと両方からコマンドを送る事になります。

Framework4.5 になって、非同期処理がイベントを作成せずに行単位で処理が継続できるようになったので、コードが簡潔に書けるようになりました。( この処理の場合非同期で行う必要は無いと思いますが )

ブラウザは、IE を使って行うといいと思います。設定で『ウェブサイトを表示するたびに確認する』としておけば、キャッシュによるトラブルも避けられます。

そもそもの目的は、Windows8 ストアアプリよりデータベースアクセスをする為のサーバーとしての利用なので、データベースアクセス用の簡単なテンプレートを用意しています。実際は、Json.NET を使って http で結果を返すつもりにしています。
using System;
using System.Collections.Generic;
using System.Data.Odbc;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CHttpServer1
{
	public class Program
	{
		// 引数
		public static string[] args;
		// DB接続文字列
		static string cs = "Driver={MySQL ODBC 5.2 Unicode Driver};" +
			"Server=localhost;" +
			"Database=lightbox;" +
			"Uid=root;" + 
			"Pwd=パスワード;";

		static void Main(string[] args)
		{
			App app = new App();

			// イベントの追加
			app.OpenDb += open;

			// ラムダ式による実装
			app.Select += (string cmd) =>
			{
				Console.WriteLine(cmd + " が実行されました");

				// select の結果を表示する
			};

			// スレッドイベントを登録
			app.ThreadServer += MyThread;

			// ******************************************
			// 終了せずに、コマンドプロンプトを保持する。
			// ( "q" で終了 )
			// ******************************************
			app.Loop();

		}

		// ******************************************
		// データーベースを開くイベント
		// ******************************************
		static private void open(string cmd )
		{
			Console.WriteLine(cmd + " が実行されました");

			using (OdbcConnection cn = new OdbcConnection(Program.cs))
			{
				try
				{
					cn.Open();
				}
				catch (Exception ex)
				{
					Console.WriteLine(ex.Message);
				}
				Console.WriteLine("State={0}", cn.State);
			}
			Console.WriteLine("処理が終了しました");
		}

		// ******************************************
		// http サーバーとしてのイベント( スレッド )
		// ******************************************
		static private async void MyThread()
		{
			Console.WriteLine("スレッドが開始されました");

			// HTTP プロトコル用リスナー
			TcpListener tl = new TcpListener(System.Net.IPAddress.Any, 8080);
			tl.Start();

			TcpClient tc = null;
			NetworkStream stream = null;
			StreamReader reader = null;
			StreamWriter writer = null;
			string line = null;
			string lineall = null;
			bool DataAvailable = true;

			while (true)
			{
				if (DataAvailable)
				{
					Console.WriteLine("受信を待機しています.....");
				}
				// HTTP の受信待ち
				tc = tl.AcceptTcpClient();

				// 以下は、受信した場合に処理されます
				// データの入り口 ( NetworkStream )
				stream = tc.GetStream();

				Thread.Sleep(500);

				// ストリームを読み込むオブジェクトを取得
				reader = new StreamReader(stream);
				// 実際にデータを読み込んで処理したかどうか
				DataAvailable = false;
				// 一回の受信で朱徳した全文字列
				lineall = "";

				// 実際の全てのデータ取得
				if (stream.DataAvailable)
				{
					// 非同期で一行取得
					while (true)
					{
						line = await reader.ReadLineAsync();
						// 空でチェックするしかないようです。
						if (line == "")
						{
							break;
						}
						lineall += line + "\n";
					}

					DataAvailable = true;
				}

				// http の返信用の書き込みオブジェクトを SHIFT_JIS で作成
				writer = new StreamWriter(stream, Encoding.GetEncoding("shift_jis"));

				// HTTP プロトコルに従って、ヘッダと本文を返す
				writer.WriteLine("HTTP/1.1 200 OK");
				writer.WriteLine("Content-Type:text/plain; charset=Shift_JIS");
				int length = (Encoding.GetEncoding("shift_jis")).GetByteCount(lineall);
				writer.WriteLine("Content-Length: " + length);

				writer.WriteLine();
				writer.WriteLine(lineall);

				// オブジェクトを閉じる
				writer.Close();
				reader.Close();
				stream.Close();

				if (lineall == "")
				{
					// Console.WriteLine("データがありません");
					continue;
				}
				Console.WriteLine(lineall);

				// アドレスバーで、http://localhost:8080/q と入力した場合はスレッドを終了
				if ( (lineall+"       ").Substring(0, 7) == "GET /q ")
				{
					tl.Stop();
					break;
				}
			}

			Console.WriteLine("スレッドが終了しました");
		}
	
	}
}

Framework 4.0 でも、static private async void MyThread() の async を削除して、line = await sr.ReadLineAsync(); を line = sr.ReadLine(); にすればビルドできます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CHttpServer1
{
	class App
	{
		public delegate void AppHandler( string cmd );
		public event AppHandler OpenDb = null;
		public event AppHandler Select = null;
		public delegate void ThreadHandler();
		public event ThreadStart ThreadServer = null;

		// ******************************************
		// コンストラクタ
		// ******************************************
		public App()
		{
		}

		// ******************************************
		// 終了せずに、コマンドプロンプトを保持する。
		// ******************************************
		public void Loop()
		{

			while (true)
			{
				// 専用プロンプト
				Console.Write("app>");
				string line = Console.ReadLine();

				// 終了コマンド
				if (line == "q")
				{
					break;
				}

				// スレッドを開始
				if (line == "server")
				{
					if (ThreadServer != null)
					{
						Thread ts = new Thread(ThreadServer);
						ts.Start();
					}

				}

				// DBを開く
				if (line == "open")
				{
					if (OpenDb != null)
					{
						OpenDb(line);
					}
				}

				// select 実行の表示
				if (line == "select")
				{
					if (Select != null)
					{
						Select(line);
					}
				}

			}
		}
	}
}

関連する記事コンソールアプリケーション(C#) で、クラス、デリゲート、イベント、ラムダ式の振舞いを理解するVB.net : クライアントが送ったヘッダを表示するだけの HTTPサーバーUHTTP コマンド・リスナー :【VB.NET】



【VS(C#)の最新記事】
posted by lightbox at 2013-09-12 16:10 | VS(C#) | このブログの読者になる | 更新情報をチェックする
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり