zoukankan      html  css  js  c++  java
  • 短信开发系列(三):短信接收引擎

    短信开发系列目录:

    短信开发系列(一):GSM手机短信开发初探
    短信开发系列(二):GSM手机短信开发之短信解码
    短信开发系列(三):短信接收引擎

    之前写了短信接收处理的一些内容,今年事情实在太多了,就停顿了这么一大段的时间。接下来会继续完成相关的内容。

    今天先写用之前写的短信类库的一个应用,短信接收引擎。可以用在处理一些短信的提醒;作为前面两篇文章的一个实战运用,可以作为一个多线程、委托和事件、串口等方面知识的一个综合运用。

    先来分析一下整个程序的流程:

    - 启动线程

    - 定时运行线程主函数

      - 测试串口是否打开,短信猫是否正常工作

      - 发送AT命令,获取所有未阅读的短信

      - 遍历每条短信,提取其内容保存到临时变量中

      - 尝试删除该短信,如果删除成功,则通知订阅者有新的短信

    这个短信接收引擎使用非常简单,你可以轻易的应用到你需要的场景中:

    复制代码
     1 /// <summary>
     2         /// 窗体加载时发生
     3         /// </summary>
     4         /// <param name="sender"></param>
     5         /// <param name="e"></param>
     6         private void MainFrm_Load(object sender, EventArgs e)
     7         {
     8             var engine = new SmsEngine(ConfigSettings.ComName)
     9                              {
    10                                  QueryInterval = ConfigSettings.QueryInterval
    11                              };
    12             engine.OnBufferRead += Engine_OnBufferRead;//读取缓冲区内容时触发
    13             engine.OnEngineException += Engine_OnEngineException;//引擎异常时触发
    14             engine.OnReceivedMessage += Engine_OnReceivedMessage;//有新的短信时触发
    15             engine.Start();
    16 
    17             tvAddr.ExpandAll();
    18         }
    复制代码

    以下是整个引擎的代码,需要的同学可以参考。涉及短信解码编码部分,请参考前面两篇文章。

    复制代码
      1 //======================================================================
      2 //
      3 //        copyright (C) 2012 All rights reserved
      4 //        framework   : 4.0   
      5 //        filename    : SmsEngine
      6 //        description :
      7 //        author      : marvin(马非马)
      8 //        company     : Sysu.im.06imis
      9 //        create time : 2012/9/5 14:19:24
     10 //
     11 //======================================================================
     12 using System;
     13 using System.IO.Ports;
     14 using System.Linq;
     15 using System.Text;
     16 using System.Threading;
     17 using System.Threading.Tasks;
     18 using Loncomip.Utility.IO;
     19 
     20 namespace Loncomip.Utility.SmsLib
     21 {
     22     public class SmsEngine
     23     {
     24         #region Event
     25         /// <summary>
     26         /// 接收到短信时处理的回调函数
     27         /// </summary>
     28         public delegate void MsgReceivedHandler(object sender, MsgReceivedEventArgs e);
     29         /// <summary>
     30         /// 从串口缓冲区中读到任何内容时的回调函数
     31         /// </summary>
     32         public delegate void ReadBufferHandler(object sender, ReadBufferEventArgs e);
     33         /// <summary>
     34         /// 短信引擎发生异常时的回调函数
     35         /// </summary>
     36         public delegate void EngineExceptionHandler(object sender, EngineExceptionEventArgs e);
     37 
     38         /// <summary>
     39         /// 
     40         /// </summary>
     41         public class MsgReceivedEventArgs : EventArgs
     42         {
     43             /// <summary>
     44             /// 发送人的号码
     45             /// </summary>
     46             /// <value>The sender no.</value>
     47             public string SenderNo { get; set; }
     48             /// <summary>
     49             /// 服务中心发送短信的时间
     50             /// </summary>
     51             /// <value>The service center send time.</value>
     52             public DateTime ServiceCenterSendTime { get; set; }
     53             /// <summary>
     54             /// 短信的内容
     55             /// </summary>
     56             /// <value>The content.</value>
     57             public string Content { get; set; }
     58             public string RawBuffer { get; set; }
     59 
     60             public MsgReceivedEventArgs(DateTime time, string no, string content)
     61             {
     62                 ServiceCenterSendTime = time;
     63                 SenderNo = no;
     64                 Content = content;
     65             }
     66         }
     67         /// <summary>
     68         /// 
     69         /// </summary>
     70         public class ReadBufferEventArgs : EventArgs
     71         {
     72             public string Buffer { get; set; }
     73             public ReadBufferEventArgs(string buffer)
     74             {
     75                 Buffer = buffer;
     76             }
     77         }
     78         /// <summary>
     79         /// 
     80         /// </summary>
     81         public class EngineExceptionEventArgs : EventArgs
     82         {
     83             public Exception Source { get; set; }
     84             public string Message { get; set; }
     85 
     86             public EngineExceptionEventArgs(Exception e, string msg)
     87             {
     88                 Source = e;
     89                 Message = msg;
     90             }
     91         }
     92 
     93         public event MsgReceivedHandler OnReceivedMessage;
     94         public event ReadBufferHandler OnBufferRead;
     95         public event EngineExceptionHandler OnEngineException;
     96         #endregion
     97 
     98         #region Fields
     99         private SerialPort _serialPort;
    100         private CancellationTokenSource _cts;
    101         private readonly string _comName;
    102         #endregion
    103 
    104         #region Construct
    105         public SmsEngine(string comName)
    106         {
    107             _comName = comName;
    108             QueryInterval = 5;
    109         }
    110 
    111         public SmsEngine(string comName, bool initCancellationTokenSource)
    112         {
    113             _comName = comName;
    114             QueryInterval = 5;
    115 
    116             if (initCancellationTokenSource) _cts = new CancellationTokenSource();
    117         }
    118         #endregion
    119 
    120         public int QueryInterval
    121         {
    122             get;
    123             set;
    124         }
    125 
    126         /// <summary>
    127         /// Starts this instance.
    128         /// </summary>
    129         public void Start()
    130         {
    131             _cts = new CancellationTokenSource();
    132             var task = new Task(Run, _cts.Token);
    133             task.Start();
    134         }
    135 
    136         /// <summary>
    137         /// Stops this instance.
    138         /// </summary>
    139         public void Stop()
    140         {
    141             _cts.Cancel();
    142         }
    143 
    144         /// <summary>
    145         /// 线程主函数
    146         /// </summary>
    147         private void Run()
    148         {
    149             while (!_cts.IsCancellationRequested)
    150             {
    151                 try
    152                 {
    153                     GetAllMsg();
    154                 }
    155                 catch (Exception e)
    156                 {
    157                     HandelEnginException(e, "线程异常:{0}", e.Message);
    158                     _cts.Token.WaitHandle.WaitOne(2 * 1000);
    159                 }
    160                 finally
    161                 {
    162                     _cts.Token.WaitHandle.WaitOne(QueryInterval * 1000);
    163                 }
    164             }
    165         }
    166 
    167         /// <summary>
    168         /// 获取所有的短信
    169         /// </summary>
    170         private void GetAllMsg()
    171         {
    172             OpenAndTestModem();
    173             WriteCmd(SMSUtil.GenCmdGetList(MessageListType.All));//获取所有未阅读的消息
    174 
    175             var result = GetResult();
    176             if (string.IsNullOrEmpty(result)) return;
    177 
    178             var list = SMSUtil.DecodeSMSGetResult(result);
    179             if (list == null || !list.Any()) return;
    180 
    181             foreach (var item in list)
    182             {
    183                 try
    184                 {
    185                     WriteCmd(SMSUtil.GenCmdDeleteMsg(item.MsgIndex));
    186                     if (SMSUtil.IsSendCmdSuccess(GetResult()))
    187                     {//成功删除之后,才添加到数据库中
    188                         NLogHelper.Trace("已成功删除短信{0}#{1},将短信添加到数据库中...", item.MsgIndex,item.SenderNo);
    189                         var handler = OnReceivedMessage;
    190                         if (handler != null) handler(this, new MsgReceivedEventArgs(item.ServiceCenterTimeStamp, item.SenderNo, item.Message) { RawBuffer = result });
    191                     }
    192                     else
    193                     {
    194                         NLogHelper.Warn("删除短信失败{0}#{1}#{2}#{3}失败", item.MsgIndex, item.SenderNo, item.ServiceCenterTimeStamp, item.Message);
    195                     }
    196                 }
    197                 catch (Exception e)
    198                 {
    199                     HandelEnginException(e, "处理单条短信:{0}异常:{1}", item.Message, e.Message);
    200                     continue;
    201                 }
    202             }
    203         }
    204 
    205         /// <summary>
    206         /// 写入命令,并返回命令是否写入成功
    207         /// </summary>
    208         /// <param name="cmd">AT命令</param>
    209         /// <param name="waitTime">每次写入命令的间隔时间</param>
    210         /// <returns>返回命令的执行情况</returns>
    211         private void WriteCmd(string cmd, int waitTime = 500)
    212         {
    213             try
    214             {
    215                 var buffer = Encoding.ASCII.GetBytes(cmd);
    216                 _serialPort.Write(buffer, 0, buffer.Length);
    217                 _cts.Token.WaitHandle.WaitOne(waitTime);
    218             }
    219             catch (Exception e)
    220             {
    221                 HandelEnginException(e, "往串口写入命令异常:{0}", e.Message);
    222             }
    223         }
    224 
    225         /// <summary>
    226         /// 获取串口中的返回值
    227         /// </summary>
    228         /// <param name="waitTime">The wait time.</param>
    229         /// <returns></returns>
    230         private string GetResult(int waitTime = 500)
    231         {
    232             var len = _serialPort.BytesToRead;
    233             var result = new StringBuilder();
    234             while (len > 0)
    235             {
    236                 var buffer = new byte[len];
    237                 _serialPort.Read(buffer, 0, len);
    238                 result.Append(Encoding.ASCII.GetString(buffer));
    239 
    240                 _cts.Token.WaitHandle.WaitOne(waitTime);
    241                 len = _serialPort.BytesToRead;
    242             }
    243             if (result.Length > 0)
    244             {
    245                 var handler = OnBufferRead;
    246                 if (handler != null) OnBufferRead(this, new ReadBufferEventArgs(result.ToString()));
    247             }
    248             return result.ToString();
    249         }
    250 
    251         /// <summary>
    252         /// 打开串口并测试串口是否正常工作
    253         /// </summary>
    254         private void OpenAndTestModem()
    255         {
    256             while (!_cts.IsCancellationRequested && _serialPort == null)
    257             {
    258                 OpenModem();
    259             }
    260             while (!_cts.IsCancellationRequested && !TestModem())
    261             {
    262 
    263             }
    264         }
    265 
    266         /// <summary>
    267         /// 测试Modem是否在工作
    268         /// </summary>
    269         /// <returns></returns>
    270         private bool TestModem()
    271         {
    272             if (_serialPort == null)
    273             {
    274                 _cts.Token.WaitHandle.WaitOne(500);
    275                 return false;
    276             }
    277 
    278             try
    279             {
    280                 WriteCmd("AT ");//确认串口是否在工作
    281                 if (!SMSUtil.IsSendCmdSuccess(GetResult())) return false;
    282 
    283                 WriteCmd(SMSUtil.GenCmdMsgFormat());
    284                 if (!SMSUtil.IsSendCmdSuccess(GetResult())) return false;//设置接收格式为PDU
    285 
    286                 return true;
    287             }
    288             catch (Exception e)
    289             {
    290                 HandelEnginException(e, "测试Modem异常:{0}", e.Message);
    291                 _cts.Token.WaitHandle.WaitOne(5 * 1000);
    292                 return false;
    293             }
    294         }
    295 
    296         /// <summary>
    297         /// 打开串口
    298         /// </summary>
    299         private void OpenModem()
    300         {
    301             try
    302             {
    303                 _serialPort = new SerialPort
    304                 {
    305                     PortName = _comName,
    306                     BaudRate = 115200,
    307                     Parity = Parity.None,
    308                     DataBits = 8,
    309                     StopBits = StopBits.One,
    310                     Handshake = Handshake.None,
    311                     RtsEnable = true,
    312                     DtrEnable = true
    313                 };
    314                 _serialPort.Open();
    315             }
    316             catch (Exception e)
    317             {
    318                 _serialPort = null;
    319 
    320                 HandelEnginException(e, "打开串口失败:{0}", e.Message);
    321                 _cts.Token.WaitHandle.WaitOne(5 * 1000);
    322             }
    323         }
    324 
    325         /// <summary>
    326         /// 处理异常
    327         /// </summary>
    328         /// <param name="e">The e.</param>
    329         /// <param name="msg">The MSG.</param>
    330         /// <param name="args">The args.</param>
    331         private void HandelEnginException(Exception e, string msg, params object[] args)
    332         {
    333             var handler = OnEngineException;
    334             if (handler != null)
    335             {
    336                 try
    337                 {
    338                     if (args.Length > 0) msg = string.Format(msg, args);
    339                     handler(this, new EngineExceptionEventArgs(e, msg));
    340                 }
    341                 catch (Exception ex)
    342                 {
    343                     NLogHelper.Warn("外部异常处理异常:{0}", ex);
    344                 }
    345 
    346             }
    347             NLogHelper.Warn(e.ToString());
    348         }
    349     }
    350 }
    复制代码
  • 相关阅读:
    mac 系统下删除目录的所有.svn文件
    java DES加密解密文件
    也许,未来需要重新规划
    android选择图片或拍照图片上传到服务器(包括上传参数)
    iOS DES ECB模式对称加密解密
    iOS开发中防止键盘挡住UITextField解决方案
    xCode 4.X 免证书真机公布及调试
    iOS 获取手机的型号,系统版本,软件名称,软件版本
    java DES ECB模式对称加密解密
    解决error: failed to launch"/private/var/mobile/Applications/XX" timed out waiting for app to launch
  • 原文地址:https://www.cnblogs.com/firecode/p/4138689.html
Copyright © 2011-2022 走看看