短信开发系列(三):短信接收引擎

短信开发系列目录:

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

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

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

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

- 启动线程

- 定时运行线程主函数

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

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

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

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

 

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

View Code
 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         }

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

 

View Code
  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 {  getset; }
 48              ///   <summary>
 49               ///  服务中心发送短信的时间
 50               ///   </summary>
 51               ///   <value> The service center send time. </value>
 52              public DateTime ServiceCenterSendTime {  getset; }
 53              ///   <summary>
 54               ///  短信的内容
 55               ///   </summary>
 56               ///   <value> The content. </value>
 57              public  string Content {  getset; }
 58              public  string RawBuffer {  getset; }
 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 {  getset; }
 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 {  getset; }
 84              public  string Message {  getset; }
 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( thisnew 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( thisnew 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\r "); // 确认串口是否在工作
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( thisnew 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 }

 

 

转载于:https://www.cnblogs.com/marvin/archive/2012/11/29/GSMReceiveEngine.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值