程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 用WCF實現對無人終端的遠程監控

用WCF實現對無人終端的遠程監控

編輯:關於.NET

最近在項目中,遇到了一個需要在遠程監視自動運行軟件的實時情況的例子。因為MS面向服務方面有 WCF,而且看了一些資料,覺得WCF比較適合這個應用。因此決定用WCF來實現這個功能。

首先,先說一下具體的應用,監控,顧名思義,有兩個方面的意思,一方面是”監”,也就是遠程要 能實時查看終端的各種情況。這裡其實指的就是被監控的要能主動的,實時的向遠程控制端發送自己的情 況。另一方面是控,即遠程端能夠發布命令控制終端進行執行。並由終端返回一定的執行信息。

而且這裡是一種一對一對多的關系,即一個終端可以被多個管理端監控。實際上一個管理端也可以監 控多個終端,在是這種分析中,我們可以明白,真正運行服務的是終端,而不是管理端。

簡單起見,假定遠程發送命令的操作是void Operation(),終端更新的操作是UpdateStatus();

這個想法,從設計到實現,經歷以下三種階段的變形。

最初的想法,是一個Service類。一個接口。即

即控制端調用operation發送命令,終端調用UpdateStatus更新狀態。

對應的,要有一定的回調,即控制端發送Operation時,終端要有一個callBack進行接收,相應的,當 終端用UpdateStatus時,控制端也要有一個callBack進行接收。

當這兩種操作被集成到一個服務中時,我們的wcf接口變成了如下結構。

namespace Geyunfei.WCF
{
    [ServiceContract(

    SessionMode = SessionMode.Required
   ,
  CallbackContract = typeof(ISeviceCallBack)
         )]
    public interface IService
    {
        [OperationContract]
        /// <summary>
        /// 遠程發送控制命令
        /// </summary>
        ///
        void Operation();

        [OperationContract]
        /// <summary>
        /// 更新狀態
        /// </summary>
        void UpdateStatus();
    }
   
    public interface ISeviceCallBack
    {

     
        void ReceiveStatus();
       
        void ReceiveCommand();
    }
    public static class Global
    {
        public static List<ISeviceCallBack> callBacks = new List<ISeviceCallBack>();
    }
    [ServiceBehavior]
    public class Service : IService,IDisposable
    {
        ISeviceCallBack callBack;
        #region IService Members
        public Service()
        {
            callBack = System.ServiceModel.OperationContext.Current.GetCallbackChannel<ISeviceCallBack> ();

            Global.callBacks.Add(callBack);
          
        }

        /// <summary>
        /// 當服務端調用這個時,向終端發命令
        /// </summary>
        public void Operation()
        {

            foreach (var r in Global.callBacks)
            {
                r.ReceiveCommand();
            }
        }
        /// <summary>
        /// 當終端調用時,向服務端發命令
        /// </summary>
        public void UpdateStatus()
        {
            foreach (var r in Global.callBacks)
            {
                r.ReceiveStatus();
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Global.callBacks.Remove(this.callBack);
        }

        #endregion
    }
}

這樣做實現起來比較方便,但是缺點也是很明顯的,因為實際上終端只需要調用updateStatus,並回 調receiveCommand,而管理端只需要調用Operation,回調receiveUpdateStatus(),現在這兩種操作同時暴 露給了終端和管理端 ,因此從設計上,這是一種不安全設計。。而且在調用相應的操作時,服務端自己 又回得到相應的callBack,讓人感到很費解。

那麼下一步的想法,顯然是把面向終端和管理端的服務進行分開。同時,用全局的變量或MSMQ進行交 互,這裡為了簡單起見,只使用了List<>,沒有使用委托。

這時,我們的設計變成了如下的形式:

namespace Geyunfei.WCF2
{
    /// <summary>
    /// 面向終端的服務
    /// </summary>
    [ServiceContract(

    SessionMode = SessionMode.Required
   ,
  CallbackContract = typeof(ITerminalSeviceCallBack )
         )]
    public interface ITerminalService
    {
        [OperationContract]
        /// <summary>
        /// 更新狀態
        /// </summary>
        void UpdateStatus();
    }

    /// <summary>
    /// 面向管理端的服務
    /// </summary>
    [ServiceContract(

    SessionMode = SessionMode.Required
   ,
  CallbackContract = typeof(IControlSeviceCallBack)
         )]
    public interface IControlService
    {
        [OperationContract]
        /// <summary>
        /// 遠程發送控制命令
        /// </summary>
        ///
        void Operation();
    }

    public interface ITerminalSeviceCallBack
    {
        void ReceiveCommand();
    }

    public interface IControlSeviceCallBack
    {
        void ReceiveStatus();
    }
    public static class Global
    {
        public static List<IControlSeviceCallBack > controlcallBacks = new List<IControlSeviceCallBack >();
        public static List<ITerminalSeviceCallBack> terminalcallBacks = new List<ITerminalSeviceCallBack>();
    }
    [ServiceBehavior]
    public class TerminalService : ITerminalService, IDisposable
    {
         ITerminalSeviceCallBack callBack;
        #region IService Members
         public TerminalService()
        {
            callBack = System.ServiceModel.OperationContext.Current.GetCallbackChannel<ITerminalSeviceCallBack&g t;();
            Global.terminalcallBacks .Add(callBack);

        }
        /// <summary>
        /// 當終端調用時,向服務端發命令
        /// </summary>
        public void UpdateStatus()
        {
            foreach (var r in Global.controlcallBacks)
            {
                r.ReceiveStatus();
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Global.terminalcallBacks .Remove(this.callBack);
        }

        #endregion
    }


    [ServiceBehavior]
    public class ControlService : IControlService, IDisposable
    {
        IControlSeviceCallBack  callBack;
        #region IService Members
        public ControlService()
        {
            callBack = System.ServiceModel.OperationContext.Current.GetCallbackChannel<IControlSeviceCallBack >();

            Global.controlcallBacks .Add(callBack);

         }

        /// <summary>
        /// 當服務端調用這個時,向終端發命令
        /// </summary>
        public void Operation()
        {

            foreach (var r in Global.terminalcallBacks)
            {
                r.ReceiveCommand();
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Global.controlcallBacks .Remove(this.callBack);
        }

        #endregion
    }
}

現在,終端和管理端的服務分開了,接口也清晰了。

但是這樣做又有另一個缺點,即我的每一個終端是只運行一個軟件的,即我在運行terminalService時 ,只有一個點在接入。這時,我為這一個點開一個服務,是一種浪費 。

於是,就有了第三種方案。即服務是面向管理端的。終端只實例一個簡單的承載體,如下:

這時,我們的方案就已經接近完美了。

namespace Geyunfei.WCF3
{
    [ServiceContract(

    SessionMode = SessionMode.Required
   ,
  CallbackContract = typeof(ISeviceCallBack)
         )]
    public interface IService
    {
        [OperationContract]
        /// <summary>
        /// 遠程發送控制命令
        /// </summary>
        void Operation();
    }

    public interface ISeviceCallBack
    {
        void ReceiveStatus();
    }
    public static class Global
    {
        public static List<ISeviceCallBack> callBacks = new List<ISeviceCallBack>();
        public static ReceiveCommandHandler receiveCommad;
    }
    [ServiceBehavior]
    public class Service : IService, IDisposable
    {
        ISeviceCallBack callBack;
        #region IService Members
        public Service()
        {
            callBack = System.ServiceModel.OperationContext.Current.GetCallbackChannel<ISeviceCallBack> ();
            Global.callBacks.Add(callBack);

        }
        /// <summary>
        /// 當終端調用時,向服務端發命令
        /// </summary>
        public void Operation()
        {

            if (Global.receiveCommad != null)
                Global.receiveCommad();
        }
        #endregion
        #region IDisposable Members
        public void Dispose()
        {
            Global.callBacks.Remove(this.callBack);
        }

        #endregion
    }


  
    public delegate void ReceiveCommandHandler();
    public class ServiceHost
    {
        public ServiceHost()
        {
        }

        public void Start()
        {
            //在這裡啟動運行一個Service服務
        }
        public void Stop()
        {
            //在這裡停止服務
        }


        /// <summary>
        /// 當收到遠程的命令時,觸發此事件
        /// </summary>
        public event ReceiveCommandHandler ReceveCommand
        {
            add
            {
                Global.receiveCommad += value;
            }
            remove
            {
                Global.receiveCommad -= value;
            }
        }


        /// <summary>
        /// 更新狀態
        /// </summary>
        public void UpdateStatus()
        {
            foreach (var r in Global.callBacks)
            {
                r.ReceiveStatus();
            }
        }

    }
}

以上是我在開發中的一些體會,從第一種到第三種,可能老鳥們看著很弱智,只接就能使用第三種設 計,但是對於一個初學者,直接想到這種方案可能比較困難,歡迎大家討論。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved