首页 > 代码库 > 短信开发系列(三):短信接收引擎

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

短信开发系列目录:

短信开发系列(一):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\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(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 }

 

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