- PR -

プロセス間通信(IPC) Remortingについて

1
投稿者投稿内容
あかり
常連さん
会議室デビュー日: 2009/02/18
投稿数: 38
投稿日時: 2009-02-25 13:22
VB.NETでプロセス間通信を行いたいのですが、うまくいきませんどこがいけないのでしょうか?
サーバーを立ち上げ、
クライアント側から、メッセージを送信しようとした場合に、
IPCポートに接続できませんとエラーが出てしまいます。

参考サイト
http://katamari.jp/index.php?dev%2Fvb%2F.NET%20Remoting%A4%F2%BB%C8%CD%D1%A4%B7%A4%BF%A5%D7%A5%ED%A5%BB%A5%B9%B4%D6%C4%CC%BF%AE

ソース
サーバー側
Private Const Port As Integer = 8088
Private Const ObjectUri As String = "RemoteObj"

Private mChannel As IpcChannel
Private mRemoteObject As RemoteObject
Private Sub IPC()

Dim provider As BinaryServerFormatterSinkProvider
Dim props As IDictionary

provider = New BinaryServerFormatterSinkProvider
provider.TypeFilterLevel = Runtime.Serialization.Formatters.TypeFilterLevel.Full

props = New Hashtable
props("port") = Port

Try
'// サーバチャネル生成
mChannel = New IpcChannel(props, Nothing, provider)

'// チャネル登録
ChannelServices.RegisterChannel(mChannel, True)

Catch exSocket As System.Net.Sockets.SocketException

Console.WriteLine(exSocket.ToString)
Exit Sub

Catch ex As Exception
Console.WriteLine(ex.ToString)
Exit Sub

End Try

'// RemoteObjectインスタンス生成
mRemoteObject = New RemoteObject

'//メッセージを受信する関数を指定
AddHandler mRemoteObject.ReceiveMessage, AddressOf ReceiveMessage

'//
RemotingServices.Marshal(mRemoteObject, ObjectUri)

End Sub

'// FormClosed
Private Sub IpcEnd()

Try
If Not mChannel Is Nothing Then
'//チャネルの登録を解除
ChannelServices.UnregisterChannel(mChannel)
End If
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try

End Sub

'// メッセージ受信
Private Sub ReceiveMessage(ByVal msg As String)

Console.WriteLine("Server ReceiveMessage: {0}", msg)
End Sub

クライアント側
Private Const ObjectUri As String = "RemoteObj"
Private Const TypeName As String = "RemoteObject, RemoteObject"
Private Const Port As Integer = 8088

Private mChannel As IPCChannel
Private mRemoteObject As RemoteObject

'// FormLoad
Private Sub Ipc()

'// クライアントチャネルのみアクティブなIPCChannelインスタンス生成
mChannel = New IPCChannel


Try
'// チャネル登録
ChannelServices.RegisterChannel(mChannel, False)
Catch ex As Exception
Console.WriteLine(ex.ToString)
Exit Sub
End Try
Dim a As New RemoteObject
Try
'// RemoteObjectインスタンス生成
'// この時点でServerプログラムが起動していなくても例外は発生しない
mRemoteObject = CType(Activator.GetObject( _
a.GetType, _
"IPC://localhost:" & Port.ToString & "/" & ObjectUri), _
RemoteObject)
Catch ex As Exception
Console.WriteLine(ex.ToString)
Exit Sub
End Try

End Sub

'// FromClosed
Private Sub IPCEnd()

Try
If Not mChannel Is Nothing Then
'//チャネルの登録を解除
ChannelServices.UnregisterChannel(mChannel)
End If
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try

End Sub

'// Send Button クリック
Private Sub msgSend(ByRef strbuf As String)
If mRemoteObject Is Nothing Then
Exit Sub
End If

Try
'// 送信
mRemoteObject.SendMessage(strbuf)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub

リモートオブジェクト
Public Class RemoteObject
Inherits MarshalByRefObject

Public Delegate Sub delReceiveMessage(ByVal str As String)
Public Event ReceiveMessage As delReceiveMessage

Public Sub SendMessage(ByVal str As String)
RaiseEvent ReceiveMessage(str)
End Sub

End Class
すけきよK20A
会議室デビュー日: 2007/11/13
投稿数: 3
投稿日時: 2009-02-27 01:22
こんにちわ。丁度IPCを試していたところで、大体思ったように動くので良かったら参考にして下さい。と、いいましてもC#なので読みなおしていただければいけませんが。。。また、あかりさんが示している方法とやや違うのですがご了承を。

プログラムにはWindowsサービスとWinアプリの2つがあります。
WindowsサービスがIPCのサーバになります。
クライアントはWinアプリとWindowsサービスの2つがあります。これがキモです。
サーバとクライアントが通信するのかと思ってたのですが、通信するのは
クライアントとクライアントで、サーバはその場を作る、みたいです。これについては
ここの投稿にもありました。

  
//
// Windowsサービス
// 仕様
// 1. OnStartで、IpcServerChannelでサーバーを登録
// 2. ACLで、AdministratorとPowerUserのみ許可
// 3. IpcClientChannelでWinアプリと通信するクライアントの登録
// 4. IPCで現在の時刻を共有する
protected override void OnStart(string[] args)
{
// TODO: サービスを開始するためのコードをここに追加します。
#region "ACL"
IDictionary props = new Hashtable();
props["portName"] = "remote";

// ACL
// Local administrators sid
SecurityIdentifier localAdminSid = new SecurityIdentifier(
WellKnownSidType.BuiltinAdministratorsSid, null);
// Local Power users sid
SecurityIdentifier powerUsersSid = new SecurityIdentifier(
WellKnownSidType.BuiltinPowerUsersSid, null);
DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, 1);

// Allow acces only from local administrators and power users
dacl.AddAccess(AccessControlType.Allow, localAdminSid, -1,
InheritanceFlags.None, PropagationFlags.None);
dacl.AddAccess(AccessControlType.Allow, powerUsersSid, -1,
InheritanceFlags.None, PropagationFlags.None);

CommonSecurityDescriptor securityDescriptor =
new CommonSecurityDescriptor(false, false,
ControlFlags.GroupDefaulted |
ControlFlags.OwnerDefaulted |
ControlFlags.DiscretionaryAclPresent,
null, null, null, dacl);

#endregion

// IPC Channelを作成
IpcServerChannel servChannel = new IpcServerChannel(
props,
null,
securityDescriptor);

// リモートオブジェクトを登録
ChannelServices.RegisterChannel(servChannel, false);

RemotingConfiguration.RegisterWellKnownServiceType(typeof (CopyNow), "copynow", WellKnownObjectMode.Singleton);

// クライアント
IpcClientChannel clientChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(clientChannel, false);

try
{
RemotingConfiguration.RegisterWellKnownClientType(typeof(CopyNow), "ipc://remote/copynow");
}
catch(Exception e)
{
}

// IPCで共有するオブジェクトの生成
// m_copyNowはフィールド
m_copyNow = new CopyNow();
m_copyNow.Msg = "Hi! Client. " + DateTime.Now.ToString();
}

//
// IPCで共有するオブジェクト
//
public class CopyNow : MarshalByRefObject
{
static string m_msg = "";

public CopyNow()
{
}

public string Msg
{
set
{
m_msg = value;
}
get
{
return m_msg;
}
}
}

//
// Winアプリ
// 仕様
// 1. ウィンドウ生成時にIpcClientChannelを登録
// 2. タイマーで定期的にサーバから情報を取得
public partial class Form1 : Form
{
// IPC
CopyNow m_copyNow = new CopyNow();

public Form1()
{
// IPC
IpcClientChannel clientChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(clientChannel);

try
{
RemotingConfiguration.RegisterWellKnownClientType(typeof(CopyNow), "ipc://remote/copynow");
}
catch(Exception e)
{
Console.WriteLine("2: " + e.Message);
}

}

//
// 例として、タイマーを使って定期的にサーバの情報を取得する
//
private void tmrServerIPC_Tick(object sender, EventArgs e)
{
if (m_copyNow != null)
{
string msg = m_copyNow.Msg;
Console.WriteLine("> " + msg);
}
}

この例ではサーバを登録したら即座にクライアントで情報を書き込んでいますが、実プログラムでは、タイマーで定期的に書き込んで、Winアプリ側も定期的に取得しています。参考になれば幸いです。

あかり
常連さん
会議室デビュー日: 2009/02/18
投稿数: 38
投稿日時: 2009-02-27 11:31
すけきよK20A様回答ありがとうございます。

難しくて、なかなか理解できませんでした。
サービスの登録から躓いてしまいました。

>サーバとクライアントが通信するのかと思ってたのですが、通信するのは
クライアントとクライアントで、サーバはその場を作る、みたいです。これについては
ここの投稿にもありました。

私もその投稿は拝見させていただきました、その折参考サイトの書き込みを見て、できるのではと考えたのですが、うまくいきませんでした。


サーバー対クライアントがうまくいきましたので、ご報告いたします。

サーバー側
'パイプ名にあたるため任意名でよい、どらえもんと入力しても成功
'クライアントと同じにすること。
Private Const Port As Integer = 8088
'通信クラス名任意名でよい、クライアントと同じにすること。
Private Const ObjectUri As String = "RemoteObj"
'System.Runtime.Remotingを参照に追加
Private mChannel As IpcServerChannel
'クラスライブラリーに分けないと、共有オブジェクトは行えない
Private mRemoteObject As ClassLibrary1.RemoteObject

Private Sub IPC()

Try
'// サーバチャネル生成
'// チャネル登録
mChannel = New System.Runtime.Remoting.Channels.Ipc.IpcServerChannel(Port)
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(mChannel, True)
System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(GetType(ClassLibrary1.RemoteObject), GetType(ClassLibrary1.RemoteObject).Name, Runtime.Remoting.WellKnownObjectMode.SingleCall)

Catch ex As Exception
Console.WriteLine(ex.ToString)
Exit Sub

End Try

'// RemoteObjectインスタンス生成
mRemoteObject = New ClassLibrary1.RemoteObject

'//メッセージを受信する関数を指定
AddHandler mRemoteObject.ReceiveMessage, AddressOf ReceiveMessage

'//
RemotingServices.Marshal(mRemoteObject, ObjectUri)

End Sub

'// FormClosed
Private Sub IpcEnd()

Try
If Not mChannel Is Nothing Then
'//チャネルの登録を解除
ChannelServices.UnregisterChannel(mChannel)
End If
Catch ex As Exception
'Console.WriteLine(ex.ToString)
End Try

End Sub

'// メッセージ受信
Private Sub ReceiveMessage(ByVal msg As String)

Console.WriteLine("Server ReceiveMessage: {0}", msg)
str = msg
End Sub


クライアント側

Private Const ObjectUri As String = "RemoteObj"
Private Const Port As Integer = 8088

Private mChannel As System.Runtime.Remoting.Channels.Ipc.IpcClientChannel
Private mRemoteObject As ClassLibrary1.RemoteObject

'// FormLoad
Private Sub Ipc()

Try
'// チャネル登録
mChannel = New System.Runtime.Remoting.Channels.Ipc.IpcClientChannel
System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(mChannel, True)

Dim obj As Object = Activator.GetObject(GetType(ClassLibrary1.RemoteObject), "ipc://" & Port & "/" & ObjectUri)
mRemoteObject = CType(obj, ClassLibrary1.RemoteObject)
Catch ex As Exception
Console.WriteLine(ex.ToString)
Exit Sub
End Try


End Sub

'// FromClosed
Private Sub IPCEnd()

Try
If Not mChannel Is Nothing Then
'//チャネルの登録を解除
ChannelServices.UnregisterChannel(mChannel)
End If
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try

End Sub

'// Send Button クリック
Private Sub msgSend(ByRef strbuf As String)
If mRemoteObject Is Nothing Then
Exit Sub
End If

Try
'// 送信
mRemoteObject.SendMessage(strbuf)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub


クラスライブラリ
Public Class RemoteObject
Inherits MarshalByRefObject

Public Delegate Sub delReceiveMessage(ByVal str As String)
Public Event ReceiveMessage As delReceiveMessage

Public Sub SendMessage(ByVal str As String)
RaiseEvent ReceiveMessage(str)
End Sub

End Class
1

スキルアップ/キャリアアップ(JOB@IT)