関連記事
- なんと!今週の土曜日も仕事してますた.来週の土曜日も仕事臭い.TCPソケット通信をゴリゴリ書いてる 【2025年08月30日(土)】
- 【ChatGPT o4】祝日なのに仕事ーバテすぎー今夜こそ絶命だーモルモルモル 【2025年03月20日(木)】
- 【#CSharp】制御系が動き出したべ 【2025年02月20日(木)】
- 【#CSharp】ひっさしぶりにガッツリなC#案件をやっているぞー 【2025年02月19日(水)】
- 今週もひたすらモノ書き #JAVA 祭りがまだまだ続く そろそろC#を書かせろー 【2024年12月04日(水)】
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サービスに対して,やりたい放題できる,はず?
いつもどおり,バグッてたらスマソ❤

コメント
【#HTVX】新型宇宙輸送船HTV-X 油井さんがロボットアームでキャッチ
【冬】来週11℃予想とか出てきてる.秋があったのか,今年(25/10/23)
【ツル】出水平野に冬の訪れを告げるツル第一陣・今季初飛来 鹿児島(25/10/21)
都城でプロ野球・ロッテ1軍が春季キャンプ実施へ
山形で開催の映画祭 監督など国内外の参加者が“芋煮”味わう
連休なんで生駒高原でコスモスを愛でてきた
連休の中日ですの.天気は良くなる方向じゃげ
【大リーグ】大谷翔平 先頭打者HR ワイルドカードシリーズ
10月に入りましたなぁ.今年もあと90日ちょっと,早い!