.net 远程处理,委托在错误的进程中被调用
.net remoting, delegate getting called in wrong process
我正在对 .net 远程处理进行一些测试,发现在使用委托时存在问题。
我有一个既是服务器又是客户端的应用程序。当用户 运行 第一次从资源管理器访问应用程序时,它 运行 作为服务器并作为客户端启动一个新进程。两者都很好。现在,当用户 运行 在服务器和客户端进程仍在 运行ning 时再次使用它时,它假设成为客户端并向服务器发送有关新进程启动的消息,然后自行终止。
一切正常,除了委托在服务器进程中执行
客户。
这是代码。
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
static RemoteObject remoteObject;
static void RegisterClient()
{
IpcClientChannel chan = new IpcClientChannel();
ChannelServices.RegisterChannel(chan, false);
remoteObject = (RemoteObject)Activator.GetObject(typeof(RemoteObject),
string.Format("ipc://{0}/{1}", PIPE_NAME, OBJECT_NAME));
}
static void RegisterServer()
{
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IpcServerChannel chan = new IpcServerChannel("", PIPE_NAME, serverProvider);
ChannelServices.RegisterChannel(chan, false);
RemotingServices.Marshal(new RemoteObject(), OBJECT_NAME);
}
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if ((args.Length == 0 || args[0] == "s"))
{
try
{
RegisterServer();
}
catch (RemotingException)
{
// try to register it with the pipe name. If it fails, means server is already running.
//bad idea, I know, but it's just for barebone quick test
RegisterClient();
remoteObject.OnNewProcessStarted("test");
Application.Exit();
return;
}
Process.Start(Application.ExecutablePath, "c");
Application.Run(new Form1("Server"));
}
else
{
IsClient = true;
RegisterClient();
remoteObject.SetOnNewProcessStarted(OnNewProcessStarted);
Application.Run(new Form1("Client"));
}
}
static bool IsClient = false;
static bool OnNewProcessStarted(string commandLine)
{
MessageBox.Show("Is Client : " + IsClient);//problem here, IsClient should be true
return true;
}
RemoteObject class.
public delegate bool OnNewProcessStartedDelegate(string text);
internal class RemoteObject : MarshalByRefObject
{
public OnNewProcessStartedDelegate OnNewProcessStartedHandler;
public bool OnNewProcessStarted(string commandLine)
{
if (OnNewProcessStartedHandler != null)
return OnNewProcessStartedHandler(commandLine);
return false;
}
public void SetOnNewProcessStarted(OnNewProcessStartedDelegate onNewProcessStarted)
{
OnNewProcessStartedHandler = onNewProcessStarted;
}
public override object InitializeLifetimeService()
{
return null;
}
}
PS : 只能有一台服务器和一台客户端。
在应用程序的第二个 运行 中,您没有在 RemoteObject 中设置委托,因此使用之前设置的委托对象(它是在您的第一个 运行 中设置的申请)。
我认为,如果您 运行 您的第二个应用程序使用 'c' 这样的命令参数,委托将在客户端进程中 运行。
代理在服务器上 运行,因为新客户端正在调用服务器上 RemoteObject 的代理。服务器和第一个客户端之间没有注册回调。服务器将不知道要回调哪个进程,因为第一个客户端中没有人在监听请求。
通常使用 WCF 等技术,我们可以拥有 DualHttpBindings,这将允许双工通信,但在这里我们没有任何回调。所以我们必须在第一个客户端中使用 RemoteObject 注册一个回调通道,这将确保在第一个客户端进程中调用委托。我已经尝试过了,它正在工作。我添加了一些进程 ID 用于调试目的。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
const string CALLBACK_PIPE_NAME = "testPipeName34";
const string CALLBACK_OBJECT_NAME = "testclient";
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if ((args.Length == 0 || args[0] == "s"))
{
try
{
IPCRegistration.RegisterServer(PIPE_NAME,OBJECT_NAME);
}
catch (RemotingException)
{
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject),PIPE_NAME,OBJECT_NAME);
remoteObject.OnNewProcessStarted("test");
Application.Exit();
return;
}
MessageBox.Show("Server:" + Process.GetCurrentProcess().Id);
Process.Start(Application.ExecutablePath, "c");
Application.Run(new Form1("Server"));
}
else
{
IsClient = true;
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject), PIPE_NAME, OBJECT_NAME);
IPCRegistration.RegisterServer(CALLBACK_PIPE_NAME, CALLBACK_OBJECT_NAME); // Here Client will listen on this channel.
remoteObject.SetOnNewProcessStarted(OnNewProcessStarted,Process.GetCurrentProcess().Id.ToString());
MessageBox.Show("Client:" + Process.GetCurrentProcess().Id);
Application.Run(new Form1("Client"));
}
}
static RemoteObject remoteObject;
static bool IsClient = false;
static bool OnNewProcessStarted(string commandLine)
{
MessageBox.Show("saved:"+commandLine+" Currrent:"+Process.GetCurrentProcess().Id);
MessageBox.Show("Is Client : " + IsClient);//problem here, IsClient should be true
return true;
}
}
public delegate bool OnNewProcessStartedDelegate(string text);
internal class RemoteObject : MarshalByRefObject
{
public OnNewProcessStartedDelegate OnNewProcessStartedHandler;
public string value;
public bool isCallBack = false;
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
const string CALLBACK_PIPE_NAME = "testPipeName34";
const string CALLBACK_OBJECT_NAME = "testclient";
RemoteObject remoteObject;
public bool OnNewProcessStarted(string commandLine)
{
if (!isCallBack)
{
remoteObject.isCallBack = true;
return remoteObject.OnNewProcessStarted(commandLine);
}
if (OnNewProcessStartedHandler != null)
return OnNewProcessStartedHandler(value);
return false;
}
public void SetOnNewProcessStarted(OnNewProcessStartedDelegate onNewProcessStarted,string value)
{
this.value = value;
OnNewProcessStartedHandler = onNewProcessStarted;
if (!isCallBack)
{
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject), CALLBACK_PIPE_NAME, CALLBACK_OBJECT_NAME);
remoteObject.isCallBack = true;
remoteObject.SetOnNewProcessStarted(onNewProcessStarted, Process.GetCurrentProcess().Id.ToString());
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
internal class IPCRegistration
{
public static RemoteObject RegisterClient(Type remoteObject,string PIPE_NAME,string OBJECT_NAME)
{
IpcClientChannel chan = new IpcClientChannel();
ChannelServices.RegisterChannel(chan, false);
RemoteObject remoteObjectInstance = (RemoteObject)Activator.GetObject(remoteObject,
string.Format("ipc://{0}/{1}", PIPE_NAME, OBJECT_NAME));
return remoteObjectInstance;
}
public static void RegisterServer(string pipeName, string objectName)
{
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IpcServerChannel chan = new IpcServerChannel("", pipeName, serverProvider);
ChannelServices.RegisterChannel(chan, false);
RemotingServices.Marshal(new RemoteObject(), objectName);
}
}
我正在对 .net 远程处理进行一些测试,发现在使用委托时存在问题。
我有一个既是服务器又是客户端的应用程序。当用户 运行 第一次从资源管理器访问应用程序时,它 运行 作为服务器并作为客户端启动一个新进程。两者都很好。现在,当用户 运行 在服务器和客户端进程仍在 运行ning 时再次使用它时,它假设成为客户端并向服务器发送有关新进程启动的消息,然后自行终止。
一切正常,除了委托在服务器进程中执行 客户。
这是代码。
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
static RemoteObject remoteObject;
static void RegisterClient()
{
IpcClientChannel chan = new IpcClientChannel();
ChannelServices.RegisterChannel(chan, false);
remoteObject = (RemoteObject)Activator.GetObject(typeof(RemoteObject),
string.Format("ipc://{0}/{1}", PIPE_NAME, OBJECT_NAME));
}
static void RegisterServer()
{
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IpcServerChannel chan = new IpcServerChannel("", PIPE_NAME, serverProvider);
ChannelServices.RegisterChannel(chan, false);
RemotingServices.Marshal(new RemoteObject(), OBJECT_NAME);
}
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if ((args.Length == 0 || args[0] == "s"))
{
try
{
RegisterServer();
}
catch (RemotingException)
{
// try to register it with the pipe name. If it fails, means server is already running.
//bad idea, I know, but it's just for barebone quick test
RegisterClient();
remoteObject.OnNewProcessStarted("test");
Application.Exit();
return;
}
Process.Start(Application.ExecutablePath, "c");
Application.Run(new Form1("Server"));
}
else
{
IsClient = true;
RegisterClient();
remoteObject.SetOnNewProcessStarted(OnNewProcessStarted);
Application.Run(new Form1("Client"));
}
}
static bool IsClient = false;
static bool OnNewProcessStarted(string commandLine)
{
MessageBox.Show("Is Client : " + IsClient);//problem here, IsClient should be true
return true;
}
RemoteObject class.
public delegate bool OnNewProcessStartedDelegate(string text);
internal class RemoteObject : MarshalByRefObject
{
public OnNewProcessStartedDelegate OnNewProcessStartedHandler;
public bool OnNewProcessStarted(string commandLine)
{
if (OnNewProcessStartedHandler != null)
return OnNewProcessStartedHandler(commandLine);
return false;
}
public void SetOnNewProcessStarted(OnNewProcessStartedDelegate onNewProcessStarted)
{
OnNewProcessStartedHandler = onNewProcessStarted;
}
public override object InitializeLifetimeService()
{
return null;
}
}
PS : 只能有一台服务器和一台客户端。
在应用程序的第二个 运行 中,您没有在 RemoteObject 中设置委托,因此使用之前设置的委托对象(它是在您的第一个 运行 中设置的申请)。
我认为,如果您 运行 您的第二个应用程序使用 'c' 这样的命令参数,委托将在客户端进程中 运行。
代理在服务器上 运行,因为新客户端正在调用服务器上 RemoteObject 的代理。服务器和第一个客户端之间没有注册回调。服务器将不知道要回调哪个进程,因为第一个客户端中没有人在监听请求。 通常使用 WCF 等技术,我们可以拥有 DualHttpBindings,这将允许双工通信,但在这里我们没有任何回调。所以我们必须在第一个客户端中使用 RemoteObject 注册一个回调通道,这将确保在第一个客户端进程中调用委托。我已经尝试过了,它正在工作。我添加了一些进程 ID 用于调试目的。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
const string CALLBACK_PIPE_NAME = "testPipeName34";
const string CALLBACK_OBJECT_NAME = "testclient";
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if ((args.Length == 0 || args[0] == "s"))
{
try
{
IPCRegistration.RegisterServer(PIPE_NAME,OBJECT_NAME);
}
catch (RemotingException)
{
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject),PIPE_NAME,OBJECT_NAME);
remoteObject.OnNewProcessStarted("test");
Application.Exit();
return;
}
MessageBox.Show("Server:" + Process.GetCurrentProcess().Id);
Process.Start(Application.ExecutablePath, "c");
Application.Run(new Form1("Server"));
}
else
{
IsClient = true;
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject), PIPE_NAME, OBJECT_NAME);
IPCRegistration.RegisterServer(CALLBACK_PIPE_NAME, CALLBACK_OBJECT_NAME); // Here Client will listen on this channel.
remoteObject.SetOnNewProcessStarted(OnNewProcessStarted,Process.GetCurrentProcess().Id.ToString());
MessageBox.Show("Client:" + Process.GetCurrentProcess().Id);
Application.Run(new Form1("Client"));
}
}
static RemoteObject remoteObject;
static bool IsClient = false;
static bool OnNewProcessStarted(string commandLine)
{
MessageBox.Show("saved:"+commandLine+" Currrent:"+Process.GetCurrentProcess().Id);
MessageBox.Show("Is Client : " + IsClient);//problem here, IsClient should be true
return true;
}
}
public delegate bool OnNewProcessStartedDelegate(string text);
internal class RemoteObject : MarshalByRefObject
{
public OnNewProcessStartedDelegate OnNewProcessStartedHandler;
public string value;
public bool isCallBack = false;
const string PIPE_NAME = "testPipeName33";
const string OBJECT_NAME = "test";
const string CALLBACK_PIPE_NAME = "testPipeName34";
const string CALLBACK_OBJECT_NAME = "testclient";
RemoteObject remoteObject;
public bool OnNewProcessStarted(string commandLine)
{
if (!isCallBack)
{
remoteObject.isCallBack = true;
return remoteObject.OnNewProcessStarted(commandLine);
}
if (OnNewProcessStartedHandler != null)
return OnNewProcessStartedHandler(value);
return false;
}
public void SetOnNewProcessStarted(OnNewProcessStartedDelegate onNewProcessStarted,string value)
{
this.value = value;
OnNewProcessStartedHandler = onNewProcessStarted;
if (!isCallBack)
{
remoteObject = IPCRegistration.RegisterClient(typeof(RemoteObject), CALLBACK_PIPE_NAME, CALLBACK_OBJECT_NAME);
remoteObject.isCallBack = true;
remoteObject.SetOnNewProcessStarted(onNewProcessStarted, Process.GetCurrentProcess().Id.ToString());
}
}
public override object InitializeLifetimeService()
{
return null;
}
}
internal class IPCRegistration
{
public static RemoteObject RegisterClient(Type remoteObject,string PIPE_NAME,string OBJECT_NAME)
{
IpcClientChannel chan = new IpcClientChannel();
ChannelServices.RegisterChannel(chan, false);
RemoteObject remoteObjectInstance = (RemoteObject)Activator.GetObject(remoteObject,
string.Format("ipc://{0}/{1}", PIPE_NAME, OBJECT_NAME));
return remoteObjectInstance;
}
public static void RegisterServer(string pipeName, string objectName)
{
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
IpcServerChannel chan = new IpcServerChannel("", pipeName, serverProvider);
ChannelServices.RegisterChannel(chan, false);
RemotingServices.Marshal(new RemoteObject(), objectName);
}
}