.net远程处理,委托在错误的进程中被调用

时间:2015-09-27 06:03:55

标签: c# .net .net-remoting

我正在使用.net远程处理进行一些测试,发现在使用委托时它存在问题。

我有一个服务器和客户端本身的应用程序。当用户第一次从资源管理器运行应用程序时,它将作为服务器运行并作为客户端启动新进程。两者都很好。现在当用户在服务器和客户端进程仍在运行时再次运行它时,它会假设成为客户端并向服务器发送有关新进程启动然后自行终止的消息。

除了委托在服务器进程中执行之外,一切正常  客户。

这是代码。

    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类。

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:只能有一台服务器和一台客户端。

2 个答案:

答案 0 :(得分:0)

在应用程序的第二次运行中,您不必在RemoteObject中设置委托,因此使用先前设置的委托对象(它是在应用程序的第一次运行中设置的)。

我认为如果你用命令参数运行第二个应用程序,比如' c'委托将在客户端进程中运行。

答案 1 :(得分:0)

Delegate正在服务器上运行,因为新客户端正在服务器上调用RemoteObject的委托。服务器和第一个客户端之间没有注册CallBack。服务器将不知道回调哪个进程,因为第一个客户端中没有人收听请求。 通常使用像WCF这样的技术我们可以使用DualHttpBindings来实现双工通信,但在这里我们没有任何CallBack。所以我们必须在第一个客户端注册一个带有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);
        }
    }