利用短信网关 + 服务程序 + 手机监控重要数据的变化


 


每个公司在运营时有很多重要的指标是实时监控的,一但出现指标变化太大,都可能是灾难故障前的预兆,所以实时监控显得非常重要,一般情况下,我们可以安排人工或写个服务之类的进行人工监控或机器监控就行了,而针对机密数据的监控或者规模小的公司,又不希望更多的人知道,投资显然是化不来的,有没有一个好方法呢。有的,本文就简单讲述一下利用短信网关+服务程序+手机监控重要数据的变化


 


    首先介绍一下,实现本系统的前提和准备条件:


1.    有支持短信发送的网关帐号和密码;


2.    该网关提供二次开发的DEMO或标准接口;


3.    会写服务程序;


 


如果以上都没问题了,就查以开工了。


再谈本系统的开发和实现环境,具体大家可以根据需要自行调整:


1. 短信网关,由于公司的RTX(QQ企业内部交流版)有个网关插件,员工可以通过发短信方式和外界联络,所以在www.mobset.com有个帐号和密码,不过该站点一个帐号只能提供一种服务,所以不能做其它用途,后与该公司联系,可以在平台http://web.mobset.com自行创建多个帐号用于不同的服务,这样帐号的问题就解决了,对方关心的是你有足够的银子存在他们的资金库里。


2. 二次开发插件,对方提供现成的,主流的开发插件全有了,http://www.mobset.com/download.htm 下载就行了,由于本人主要用C#进行开发,所以只提取了C#部分,里边有现成的Demo ,稍懂一点的人就知道是怎么回事了,对方提供的只是一个短信调用的接口,采用dllimport逐个引入那个接口,在C#中就可调用需要的函数了;


3. 服务程序写就更简单了,我用的是VS2005进行开发的,所以在网上参考了几篇文章,很快就上手了。


 


下面把整个过程写一下来,供大家参考:


 


1) 新建项目,打开VS2003 运行IDE环境->新建->项目->Windows C# 项目->Windows->Windows 服务项目,输入项目名称->打开


2) 此时生成一些相关的文件;


其中有二个文件是我们关心的:


program.cs 运行服务时的入口文件,基本不修改,如果是几个服务要处理的,可以逐个加容器里;


service1.cs 服务具体逻辑处理部分,如服务的启动,关闭等处理;


           常见的处理如下: OnStart(string[] args) 服务启动时做什么


                         OnStop() 服务结束时做什么


3) 除此之外,默认的程序编译好后,需要对该程序进行安装,设计等工作,如该服务运行的帐号,密码,运行时是手工启动,还是自启动等都在这里可以事先设定,所以先加入安装程序,方法是打开双击Service1.cs 在窗口中右击鼠标,点击“添加安装程序”,系统会生成相关的项目文件,其中projectinstaller.designer.cs 是我们所关心的我们要在InitializeComponent添加几句话。


this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; // 
 服务运行时依赖的帐号类型
 

    

 
this.serviceProcessInstaller1.Password = null; // 
 服务运行密码
 
this.serviceProcessInstaller1.Username = null; // 
 帐号名
 
// 
 
// serviceInstaller1
 
// 
 
this.serviceInstaller1.ServiceName = " 
 平台XXXX监控" 
 ; // 
 服务名称
 
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic; // 
 默认启动方式


 


 


3) 添加业务逻辑


本系统要添加的处理逻辑流程主要如下:


3 .1启动定时器,默认是15分钟提取指标一次


3 .2 15分钟到了从数据库中取出参数指标


3 .3 记录取出的结果


3 .4 根据返回的要求决定是否发送短信


3 .5循环3.1


 


为此,根据流程分别添加了相关的类:


1. Cls_DBConnect.cs 负责连接和释放数据库


public bool
 
    {
 
string ConnString = "Server=*.*.*.*;uid=sa;pwd=********;database=yourdb";
 
        FConnString = ConnString;
 
new SqlConnection(FConnString);
 
return true;
 
    }
 
public bool
 

    

 
public void


 


 


2. Cls_DbProvide.cs 负责与数据库进行操作


public SqlConnection 
 提供一个DB连接
 
    {
 
Cls_DBConnect cls_DBConnect = new Cls_DBConnect();
 
        cls_DBConnect.GetConn();
 
SqlConnection
 
return
 
 }
 
public bool GetNeedInfo( out string 
 获取指标
 
    {
 
"";
 
SqlConnection
 
try
 
        {
 
SqlCommand SqlCmd = new SqlCommand();
 
            SqlCmd.Connection = FSqlConn;
 
CommandType.StoredProcedure;
 
" 
 存储过程" 
 ;
 
SqlParameter sqlParam = new SqlParameter();
 
new System.Data.SqlClient.SqlParameter("RETURN VALUE", SqlDbType.Int));
 
ParameterDirection.ReturnValue;
 
new System.Data.SqlClient.SqlParameter("@strOutPut", SqlDbType.VarChar, 128));
 
ParameterDirection.Output;
 
            FSqlConn.Open ();
 
            SqlCmd.ExecuteNonQuery();
 
int intRet= (int)SqlCmd.Parameters["RETURN VALUE"].Value;
 
string)SqlCmd.Parameters["@strOutPut"].Value;
 
return
 
        }
 
catch(System.Exception
 
        {
 
LogWirter logWirter = new LogWirter();
 
            //logWirter.LogEvent(ex.Message ); // 
 捕捉错误
 
" 
 网络故障,请稍后再试!" 
 ;
 
        }
 
finally
 
        {
 
            FSqlConn.Close();
 
            FSqlConn.Dispose();
 
        }
 
return true
 
       }


 


 


3. Log.cs 负责记录日志到系统日志中;


public void LogEvent(string 
 记录日志,方便调试
 
        {
 
if (!EventLog.SourceExists(eventSourceName))
 
            {
 
EventLog.CreateEventSource(eventSourceName, "Application");
 
            }
 
EventLog.WriteEntry(eventSourceName, message, EventLogEntryType.Error);
 
        }


 


4. include.cs 负责短信的插件的加载,提供对应函数


DllImport( "SmsSdk.dll")]// 
 连接短信平台服务器并登录
 
public static extern int Sms_Connect(string pServer,int lCorpID,string pLoginName, string pPasswd , int lTimeOut, IntPtr
 
………


5. SendMessage.cs 负责短信网关的连接验证,短信发送,关闭连接工作


public void 
 连接短信网关
 
        {
 
// public static extern long Sms_Connect(string pServer , long lCorpID,string pLoginName, 
 
// string pPasswd , long lTimeOut, HWND hWnd );
 
if (!this.connState)
 
            {
 
//  
 连接短信平台服务器并登录
 
string pServer = "www.mobset.com";
 
int
 
string pLonginName ="*****";
 
string pPasswd = "****";
 
int
 
IntPtr hWnd = (IntPtr)0;// include.FindWindow(null, " 
 短信接口测试");//获得当前的窗口句柄
 
int returnValue = sendmessage.include.Sms_Connect(pServer, lCorpID, pLonginName, pPasswd, lTimeOut, hWnd);
 
string strResult = "";
 
switch
 
                {
 
case
 
" 
 初始化成功!!" 
 ;
 
this.connState = !this.connState;
 

    

 
break;
 
case
 
" 
 连接服务器失败!!" 
 ;
 
break;
 
case
 
…………..
 
}
 
public void 
 关闭网关
 
        {
 
include.Sms_DisConnect();
 
this.connState = !this.connState;
 
        }
 
public void SendMessages(string 
 发送消息
 
        {
 
if (strMsg.Trim() == "") return;
 
 
 
string pMobile = "your handmobile";
 
string
 
int
 

    

 
int returnValue = sendmessage.include.Sms_Send(pMobile, pMsg, out
 

    

 
string strResult = "";
 

    

 
if
 
            {
 
" 
 发送成功!!如果没有收到可能是因为帐号到期或帐号余额不足!/n短信ID" 
  + lSmsID.ToString();
 
            }
 
Else
 
………..
 
}


 


4 )最后谁来将这些流程整合在一起呢,当然是定时器啦,定时器在service1.cs 中onstart()开启,时间到了触法事件,


private void OnTimedEvent(object sender, EventArgs
 
{
 
// 
 取数据
 
try
 
Cls_DbProvide cls_DbProvide = new Cls_DbProvide();
 
string strOutMsg = string.Empty;
 
//LogWirter logWirter = new LogWirter();
 
//logWirter.LogEvent(" 
 客户端开始取数据...");
 
if (!cls_DbProvide.GetTotalAmountMsg(out
 
// 
 发短信
 
//LogWirter logWirter = new LogWirter();
 
//logWirter.LogEvent(" 
 发短信:"+strOutMsg );
 
SendMessage sendMessage = new SendMessage();
 
                    sendMessage.connectAgent();
 
                    sendMessage.SendMessages(strOutMsg);
 
                    sendMessage.closeAgent();
 
                }
 
            }
 
catch(System.Exception
 
LogWirter logWirter = new LogWirter();
 
                logWirter.LogEvent(ex.Message ); }}


不过定时器也要有讲究的哦,后面将说明。


 


 


5 )以上都准备好了,就可以编译了,编译之前先将短信插件拷入指定的debug或release下面,目的是能顺利加载,否则提示出错,系统会生成相关的文件,不过只是一组文件,不会运行的,更不会进行调试,如果顺利通过,恭喜你可以进入布部署阶段;


 


6 )为了方便处理,我是将生成的文件复制到一个新的目录:


D:/monitor> 中,


运行部署命令,视你的.net frame开发版本而定,我是VS2005下开发的,因而选择执行


C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe Monit


or.exe


如果部署成功,系统会提示成功;


 


到此就认为是基本结束了


 


7 )在实际开发过程中会遇到很多难题,为了避免大家走我的相同的弯路,下面就说说:


1 .定时器选择什么,目前VS中的定时器有三种,通过测试,窗体中的定时器是不可用的,尽管编译不会出错,但实际上根本没有用;另外有人建议用组件中定时器,我测试也是没用的,拖进来还是form下面的,不知怎么回事,最后直接定义系统的 System.Timers.Timer timer1 = new System.Timers.Timer(900000); 才成功,


当然定义定时器后,还要绑定其事件,        


public 
  Service1()
 
        {
 
            InitializeComponent();
 
new ElapsedEventHandler(OnTimedEvent);  // 
 定时器事件
 
        }


 


2. 如何调试服务,当你写好服务后,等半天都没收到一个短信,即使故意让事件发生,也没有消息,说是服务是存在问题的,如何找到这些问题,VS2005对服务的调试比较复杂,网上也查了不少文章,各有方法,我觉得太复杂了,这里推荐大家记录事件日志的方法,来进行调试,在关键点上加上日志记录就行了,这样我们部署时可以打开事件查看器可以看到错误信息了,等调试通过后可以适当清理掉;


 


3. 要注意短信网关供应商默认深夜是不发送信息的,所以根据需要需提出申请,我也是问了半天才知道的;


 


4 .如何卸载服务,在部署命令中加参数 /u 即可


C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe /u Mo


nitor.exe


5 .默认部署服务后尽管是设为自动启动,但自启动是指启动服务器后自动启动,所以刚开始部署还是通过手工来启动


6 .写成服务的好处是让系统能够自动启动,减少手工维护,也减少出错的概率(例如不小心注销帐号),而且即使服务出错还会自动重启, 视你的设定。


 


最后目前该系统运行良好,只是功能单一,还有很多功能未添加,如发指令取数据等,当然上面的内容不全准确,尽供参考,需要源码者与我联系。


LiveCoach


2007-12-16