関連記事
- 今週もひたすらモノ書き #JAVA 祭りがまだまだ続く そろそろC#を書かせろー 【2024年12月04日(水)】
- 【#CSHARP】ソリューション内でサービス,Winformアプリを混在で作成させ,バイナリ出力先を同じにするとサービスが起動しない 【2024年02月08日(木)】
- 【#PHP】謎な #Laravel 案件 引き渡したじ 【2024年01月11日(木)】
- 【C#】謎な改造アプリ,SIMD命令を導入して高速化しようか,思案中 【2023年11月14日(火)】
- Javaの”やらかし”でC#と人気逆転か 激変プログラミング言語人気ランキング 【2023年10月18日(水)】
IPCでの実装は大昔やってたけど
今回はWCF(Windows Communication Foundation)で実装,
んでWindowsサービスとの通信までやってしまおうか,と
(ローカルPC,リモートPCからWindowsのサービスを制御してしまえ!)
IPC版のプロセス間通信のやり方はこちら
こちらのサイトを参考にしましたです
WCF入門-001 (簡単なサンプル, 自己ホスト形式, コードで記述)@いろいろ備忘録日記さん
WindowsサービスをC#で書く@backyard of 伊勢的新常識さん
Windowsサービス側(かつWCFのホスト側)
WCFの通信で利用するサービスメソッドのエンドポイントインターフェースの定義
namespace WCFWinService.Classes.WCF { //NamespaceのURLは一意な適当URLでよろしいとのこと [ServiceContract(Namespace="http://WCFWinService.Samples.WCF/")] public interface IWCFWinServiceCore { //Serviceメソッドの定義 //WCFにてサービスメソッドとして公開するメソッドはOperationContract属性を付与 [OperationContract] string OutputLogStr(string Str); [OperationContract] string AddValue(int v); [OperationContract] string ResultValue(); } }上で定義したインターフェースはクライアント側でも利用します
んで,このインターフェースの実装部を定義
namespace WCFWinService.Classes.WCF { public class ClassWCFWinServiceCore: IWCFWinServiceCore { public static System.Diagnostics.EventLog EventLog = null; public static int AddValueI = 0; public static int TickValue = 0; public string OutputLogStr(string Str) { EventLog.WriteEntry(Str); return "ACK"; } public string AddValue(int v) { AddValueI = v; return "ACK"; } public string ResultValue() { string Result = "ACK "; int tmpV = TickValue + AddValueI; Result += tmpV.ToString(); return Result; } } }staticな変数は上位層とのやり取りのために定義しましたです
んで,こいつをWindwosサービス部にてインスタンスを生成して使用します
namespace WCFWinService { public partial class WCFWinServiceMain : ServiceBase { private const string SERVICE_BASE_ADDRESS = @"net.tcp://localhost:10001/WCFWinService"; private const string ENDPOINT_OUTPUTLOGSTR = "OutputLogStr"; private const string ENDPOINT_ADDVALUE = "AddValue"; private const string ENDPOINT_RESULTVALUE = "ResultValue"; private bool m_ServiceStartFL; private bool m_ServiceTimerJobRunFL; private ServiceHost m_host; //******************************** //WinServiceコンストラクタ // // //******************************** public WCFWinServiceMain() { InitializeComponent(); m_ServiceStartFL = false; m_host = null; m_ServiceTimerJobRunFL = false; } //******************************** //WinServiceスタート // // //******************************** protected override void OnStart(string[] args) { m_ServiceStartFL = true; TMR_Main.Enabled = true; m_ServiceTimerJobRunFL = false; m_host = null; } //******************************** //WinService終了 // // //******************************** protected override void OnStop() { m_ServiceStartFL = false; TMR_Main.Enabled = false; if (m_host != null) { m_host.Close(); m_host = null; } } //******************************** //WinService タイマイベント // // //******************************** private void TMR_Main_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (m_ServiceStartFL == false) { return; } if (m_ServiceTimerJobRunFL == true) { return; } m_ServiceTimerJobRunFL = true; try { if (m_host == null) { ClassWCFWinServiceCore.EventLog = EVL_Main; //アプリケーション構成ファイルを利用せず、ServiceHostを構築する場合は //以下の情報を与える必要がある。 // ・サービスの型(インターフェースではなく、実装クラス) // ・ベースアドレス Type serviceType = typeof(ClassWCFWinServiceCore); Uri baseAddress = new Uri(SERVICE_BASE_ADDRESS); m_host = new ServiceHost(serviceType, baseAddress); m_host.Opened += M_host_Opened; NetTcpBinding binding = new NetTcpBinding( SecurityMode.None, false); //net.tcpでバインド作成 Type contract = typeof(IWCFWinServiceCore); ServiceEndpoint ed1 = m_host.AddServiceEndpoint(contract, binding, ENDPOINT_OUTPUTLOGSTR ); ServiceEndpoint ed2 = m_host.AddServiceEndpoint(contract, binding, ENDPOINT_ADDVALUE ); ServiceEndpoint ed3 = m_host.AddServiceEndpoint(contract, binding, ENDPOINT_RESULTVALUE ); m_host.Open(); } int v = ClassWCFWinServiceCore.TickValue; v++; if (v > 100000) { v = 0; } ClassWCFWinServiceCore.TickValue = v; } catch { m_host = null; } finally { m_ServiceTimerJobRunFL = false; } } //******************************** // HOSTオープン後イベント // // //******************************** private void M_host_Opened(object sender, EventArgs e) { //throw new NotImplementedException(); } } }今回はNetTcpBindingを利用しましたです
httpとかpipeとかも使える模様
Windowsサービスのスケルトン作成方法は↑のリンクを見てね♪
クライアント側
Winフォームにて実装しましたです
namespace WCFClient { public partial class Form1 : Form { private const string SERVICE_BASE_ADDRESS = @"net.tcp://192.168.1.150:10001/WCFWinService/"; private const string ENDPOINT_OUTPUTLOGSTR = "OutputLogStr"; private const string ENDPOINT_ADDVALUE = "AddValue"; private const string ENDPOINT_RESULTVALUE = "ResultValue"; public enum SeverSendMode { LogWrite, AddValue, ResultValue } public Form1() { InitializeComponent(); LBLResult.Text = ""; } private void BtnEventLogW_Click(object sender, EventArgs e) { string st = ServerSendCore(SeverSendMode.LogWrite, TxtEventLogW.Text, 0); LBLResult.Text = st; } private void BtnAddValueI_Click(object sender, EventArgs e) { int v = 0; if (int.TryParse(TxtAddValue.Text, out v) == false) { v = 0; } string st = ServerSendCore(SeverSendMode.AddValue, "", v); LBLResult.Text = st; } private void BtnResultValue_Click(object sender, EventArgs e) { string st = ServerSendCore(SeverSendMode.ResultValue, "", 0); LBLResult.Text = st; } //******************************** //ホストへの送信部主処理 // // //******************************** private string ServerSendCore(SeverSendMode md, string LogStr, int vi) { string Result = ""; string AddStr = ""; switch(md) { case SeverSendMode.LogWrite: AddStr = ENDPOINT_OUTPUTLOGSTR; break; case SeverSendMode.AddValue: AddStr = ENDPOINT_ADDVALUE; break; case SeverSendMode.ResultValue: AddStr = ENDPOINT_RESULTVALUE; break; } // エンドポイントアドレスの構築. EndpointAddress endpointAddr = new EndpointAddress(SERVICE_BASE_ADDRESS + AddStr); try { NetTcpBinding myBinding = new NetTcpBinding(); myBinding.Security.Mode = SecurityMode.None; // チャネルを構築しサービス呼び出しを行う using (ChannelFactory<IWCFWinServiceCore> channel = new ChannelFactory<IWCFWinServiceCore>(myBinding)) { // サービスへのプロキシを取得 IWCFWinServiceCore service = channel.CreateChannel(endpointAddr); // モードに合わせてサービスメソッド呼び出し switch(md) { case SeverSendMode.LogWrite: Result = service.OutputLogStr(LogStr); break; case SeverSendMode.AddValue: Result = service.AddValue(vi); break; case SeverSendMode.ResultValue: Result = service.ResultValue(); break; } // チャネルを閉じる channel.Close(); } } catch (CommunicationException ex) { // エラーが発生 MessageBox.Show(ex.Message); } return Result; } } }Windowsサービスは必ず,コマンドプロンプトでレジストの必要があります(WindowsサービスのExe名が「WCFWinService.exe」の場合)
installutil (フルパス)¥WCFWinService.exe
installutil.exeは.NetFrameworkのインストールされた場所に同梱されています
コンパイルオプションによって,32bit/64bit また,NetFrameworkのバージョンにあわせて,適時準備してくださいませ
(組み合わせが合わない場合,レジスト時,BadImageFormatExceptionな例外発生しまする)
ローカルPC内でプロセス間通信する場合は,これで終わりですけど
外部PCからリモートにてプロセス間通信する場合は,ファイアーウォールを適時設定してください
コマンドプロンプトでやる場合は,こんな感じ(WCFWinService.exeの場合.んで,exeと同フォルダにて実行)
netsh advfirewall firewall add rule name="WCFWinService" dir=in action=allow program="%~dp0WCFWinService.exe" enable=yes protocol=TCP localport=10001あと,これは片方向のみ.
双方向で通信したい場合(サービス発でクライアントに情報を送りたい)は
これの逆をWindowsサービス側とクライアントに各々実装すれば,いいはず?(やってないんで判らん:爆)
全ソースをアップしておきますーこちらですー
(ポートを開けるバッチも入れておきました)
これでWindowsサービスに対して,やりたい放題できる,はず?
いつもどおり,バグッてたらスマソ❤
コメント
【#閃輝暗点】閃輝暗点が始まった!いつもどおり目が見えなくなってるー(汗
【#イプシロン】イプシロンSロケット 燃焼試験中に爆発事故発生
あっちもこっちも風邪が流行ってるの.外に出たら感染する勢い!
【訃報】俳優 火野正平さん死去 75歳
【地震】日向灘でM4.4の地震
【#第三次世界大戦】ウクライナ空軍 “ICBM1発がロシア南部から発射された”
司法省 “グーグルはクローム売却を” 裁判所に要求へ 米報道
最近,仕事がずっと激しい...ドロドロドロ
今日は謎の宴会らしい...スーツが入るのかっ!?(GRB爆
「侍ジャパン」宮崎県入り 「プレミア12」向け きょうから合宿