Reminder[短信提示工具]开发碎碎念。。。附带感谢移动[smtp.139.com]提供的免费午餐。。

  Reminder是我最近开发的一个股票行情短信提示软件(刚做完,还是不够稳定。。)。开发这个小东东的想法缘起前段时间在首页看到一篇介绍开放Web Service的文章,其中有个Web Service就是获取实时股票行情的,看到后突然有了做个行情短信提示软件的想法,主要也是由于个人需求驱动,接着。。。革命开始了。。

  Reminder的基础功能很简单:

  1、实时获取股票行情;

  2、根据股票行情判断是否需要进行提示;

  3、发送短信提示;

  

  可是做起来也挺花时间。。。。接下来逐一介绍吧,这里主要提供思路,代码比较简单,也完成的比较仓促,就不全发了。

  1、获取股票行情

  虽然做Reminder的想法缘起Web Service,不过最后实现的时候是调用了新浪的股票行情接口, 之所以选用后者处于两方面的原因:第一,出于稳定性的考虑,觉得新浪比较靠谱。。第二,个人感觉使用更方便一点,并且一次访问可以提取多个股票行情,配置多只股票的话,访问次数少。代码很简单:

 1           ///   <summary>
 2           ///  发出http get请求 获取返回的信息
 3           ///   </summary>
 4           ///   <param name="url"> 例: http://hq.sinajs.cn/list=sh0000001 </param>
 5           ///   <returns></returns>
 6           public   string  HttpGet( string  url)
 7          {
 8               string [] list  =   new   string [ 2 ];
 9              HttpWebRequest request  =   null ;
10              HttpWebResponse response  =   null ;
11               string  responseHTML  =   string .Empty;
12 
13              request  =  (HttpWebRequest)WebRequest.Create(url);
14              request.Method  =   " GET " ;
15               // 返回HTML
16              response  =  (HttpWebResponse)request.GetResponse();
17              Stream dataStream  =  response.GetResponseStream();
18              StreamReader reader  =   new  StreamReader(dataStream, Encoding.GetEncoding( " gb2312 " ));
19              responseHTML  =  reader.ReadToEnd();
20 
21               return  responseHTML;
22          }

  得到返回的HTML之后当然就是进行处理,这里只贴出返回数据的格式,具体应用中要如何定义数据结构请自便。。

返回的HTML
  ///   <summary>
        
///  解析从 WebRequest返回的HTML数据,将其处理成为StockInfo对象
        
///   </summary>
        
///   <param name="stockHtml">        
        
///  返回的HTML:
        
/// var hq_str_sh601003 = " 柳钢股份,5.04,5.05,5.24,5.50,4.96,5.24,5.25,16079772,84917716,11047,5.24,
        
///  53100,5.23,30300,5.22,24400,5.21,93000,5.20,54500,5.25,44600,5.26,48943,5.27,41154,5.28,40170,
        
///  5.29,2010-08-24,15:02:07";
        
///  
        
/// 0:”大秦铁路”,股票名字;
        
/// 1:”27.55″,今日开盘价;
        
/// 2:”27.25″ ,昨日收盘价;
        
/// 3:”26.91″,当前价格;
        
/// 4:”27.55″,今日最高价;
        
/// 5:”26.20″ ,今日最低价;
        
/// 6:”26.91″,竞买价,即“买一”报价;
        
/// 7:”26.92″ ,竞卖价,即“卖一”报价;
        
/// 8:”22114263″ ,成交的股票数,由于股票交易以一百股为基本单位,所以在使用时,通常把该值除以一百;
        
/// 9:”589824680″ ,成交金额,单位为“元”,为了一目了然,通常以“万元”为成交金额的单位,所以通常把该值除以一万;
        
/// 10:”4695″,“买一”申请4695 股,即47手;
        
/// 11:”26.91″,“买一”报价;
        
/// 12:”57590″ ,“买二”
        
/// 13:”26.90″,“买二”
        
/// 14:”14700″ ,“买三”
        
/// 15:”26.89″ ,“买三”
        
/// 16:”14300″,“买四”
        
/// 17:”26.88″,“买四”
        
/// 18:”15100″ , “买五”
        
/// 19:”26.87″,“买五”
        
/// 20:”3100″,“卖一”申报3100股,即31手;
        
/// 21:”26.92″,“卖一”报价
        
/// (22, 23), (24, 25), (26,27), (28, 29) 分别为“卖二”至“卖四的情况”
        
/// 30:”2008-01-11″ ,日期;
        
/// 31:”15:05:32″,时间; </param>
        
///   <returns></returns>
         private  Dictionary < string  ,StockInfo >  stockHtmlDeal( string  stockHtml)

  2、根据股票行情判断是否需要进行提示;

  定义一个timer对象,一段时间对新浪股票行情接口访问一次,根据自己的需要编写股票行情提示条件判断方法【判断方法不在此赘述】,每个一段时间调用一次:

 1           ///   <summary>
 2           ///  定时器
 3           ///   </summary>
 4          System.Timers.Timer Time  =   new  System.Timers.Timer( 30000 ); // 1000为1秒
 5 
 6           private   void  TimeSet()
 7          {
 8              Time.Elapsed  +=   new  ElapsedEventHandler(ListenerToStock);
 9              Time.AutoReset  =   true ; // 设置是执行一次(false)还是一直执行(true); 
10              Time.Enabled  =   true ; // 是否执行System.Timers.Timer.Elapsed事件;
11          }
12 
13           private   void  ListenerToStock( object  sender, ElapsedEventArgs e)
14          {
15                // todo:读股票行情,根据一定算法,判断是否发送提示信息。
16          }

  3、发送短信提示;

  这个部分花费了我大量时间。。并且目前还没达到自己满意的程度,如有可能,还会在这个环节的处理继续加强。

  不过就这部分的开发来说,对我来说是挺有趣的。

  A、现实如此残酷。。。

  开发之前的想法,是以前经常看到一些Fetion的接口,觉得发短信很简单的,找个来调用就可以了,真到了要用的时候,发现网络上基本没有能发送成功的接口。。小弟不才,如果哪位大哥知道,请指点一下,不胜感激~~~~

  B、免费的午餐。。。不怎么可口

  颇费了一番周折之后,基本放弃了调用Fetion接口发短信的想法,折腾中看到免费的午餐 ——编程利用Google日历API发短信、Email,心花怒放,赶紧下了Google Data API,摸索一下Google Calendar的使用,用上了,收到短信提示的时候那叫一个开心~~

  小小Reminder终于快要见到曙光了 ~~~~

   然而,没开心多久,免费的午餐还是不那么好吃的。。。Google Calendar的SMS提示功能用起来很不稳定(可能也是我插入数据频繁),经常延迟很久甚至收不到消息,并且短信提示的内容也不够多(应该说是比较短) ,做到后期,基本感觉到如果用谷歌的提示,Reminder是没什么实用性了。。

  C、终于吃到了可口的免费的午餐

  最后我又想到了Fetion 。。。折腾阿。。想分析一些在用的飞信第三方软件,还特地跑到一个同学那里去请教请教,他做通信方面的,这方面比我强是肯定。。看到他用的139.com邮箱,里面有飞信功能,回家后自己也注册一个,居然看到还有新邮件免费短信提醒功能!!

上图。。。

Reminder[短信提示工具]开发碎碎念。。。附带感谢移动[smtp.139.com]提供的免费午餐。。_第1张图片 

 Reminder[短信提示工具]开发碎碎念。。。附带感谢移动[smtp.139.com]提供的免费午餐。。_第2张图片

  我笑了。。。。真是踏破铁鞋无觅处,得来全不费工夫阿。。。。没那么时间去搞协议分析,真要搞怕要搞到明年了。。。我还是捡现成的吧。。。设置了短信提醒功能后,写个发邮件的方法,用发邮件触发移动的短信提示,而且提示的内容还相当全。。。搞定~出于偷懒的原因。。代码中直接写入了自己的邮箱信息,当然密码是加密了的,配置文件中配置toMailAddress,如果多个用户的话,相当于用我的邮箱往多个指定邮箱发邮件而已。

发送邮件
  1   using  System;
 
2   using  System.Collections.Generic;
 
3   using  System.Text;
 
4   using  System.Net.Mail;
 
5   using  System.Net;
 
6   namespace  ReminderService
 
7  {
 
8       public   class  ReminderExtend 
 
9      {
10            private   static   string  from  =   " ××××××@139.com " ; // 发件人邮件地址
11            private   static   string  userName  =   " ××××××@139.com " ; // 登录smtp主机时用到的用户名,注意是邮件地址'@'以前的部分
12            private   static   string  password  =   " ×××××× " ; // 登录smtp主机时用到的用户密码
13            private   static   string  smtpHost  =   " smtp.139.com " ; // 发送邮件用到的smtp主机
14  
15           ///   <summary>
16           ///  发送邮件
17           ///   </summary>
18           ///   <param name="to"> 收件人邮件地址 </param>
19           ///   <param name="from"> 发件人邮件地址 </param>
20           ///   <param name="subject"> 邮件主题 </param>
21           ///   <param name="body"> 邮件内容 </param>
22           ///   <param name="username"> 登录smtp主机时用到的用户名,注意是邮件地址'@'以前的部分 </param>
23           ///   <param name="password"> 登录smtp主机时用到的用户密码 </param>
24           ///   <param name="smtpHost"> 发送邮件用到的smtp主机 </param>
25           public   static   void  Send( string  to,  string  subject,  string  body)
26          {
27               try
28              {
29                  MailAddress _from  =   new  MailAddress(from);
30                  MailAddress _to  =   new  MailAddress(to);
31                  MailMessage message  =   new  MailMessage(_from, _to);
32                  message.Subject  =  subject; // 设置邮件主题
33                  message.IsBodyHtml  =   true ; // 设置邮件正文为html格式
34                  message.Body  =  body; // 设置邮件内容
35                  SmtpClient client  =   new  SmtpClient(smtpHost);
36                   // 设置发送邮件身份验证方式
37                   // 注意如果发件人地址是[email protected],则用户名是abc而不是[email protected]
38                  client.Credentials  =   new  NetworkCredential(userName, password);
39                  client.Send(message);
40              }
41               catch
42              { 要写日志还是干什么自己决定吧。。。}
43          }
44           public   static   void  SendList(List < string >  toMailList,  string  subject,  string  body)
45          {
46               foreach  ( string  to  in  toMailList)
47              {
48                  Send(to, subject, body);
49              }
50          }
51      }
52  } 

  用移动的邮箱发短信,爽就一个字。。。短信世家应该也不缺这点短信吧,嘎嘎。。。邮箱刚发出去,短信就到了~~~我真有种写一篇《免费的午餐  续》来歌颂下移动的冲动。。。太贴心了~~


  为了软件的使用方便【配置股票代码,配置邮箱等】以及“安全”,还有一些附属功能

  【附:由于个人原因,我正常上班时间没有电脑可用。。。只好让小小Reminder寄生在女朋友上班用的电脑上。。太邪恶了。。】

  1、配置使用者信息;

  2、配置股票代码信息;

  3、设置开机启动;

  4、启动时即最小化到托盘;  

 

  1、读,写XML配置文件,惭愧的发现以前还真没怎么深入过,亲手做了一下,算是对XPath有了一定认识了。

  2、设置开机启动,就是写注册表,没有做成启动时就设置,而是在winform界面做了个 设置/取消  开机启动的按钮。。。咱不是流氓软件哈
    3、启动时即最小化到托盘花了一些时间,也和工作中主要是进行ASP.NET的开发,Winform做的比较少有关系吧。
最后实现的方法感觉还行,定义了一个类继承ApplicationContext,然后调用Application.Run(ApplicationContext context)方法,跳过了Application.Run(Form mainForm)强制显示form的处理。【简单的在程序中设置form的visible属性解决不了这个问题,因为最后还是会被强制显示

贴代码了。。

代码
 1  using  System;
 2  using  System.Collections.Generic;
 3 
 4  using  System.Windows.Forms;
 5 
 6  namespace  ReminderService
 7  {
 8       static   class  Program
 9      {
10           ///   <summary>
11           ///  应用程序的主入口点。
12           ///   </summary>
13          [STAThread]
14           static   void  Main()
15          {
16              Application.EnableVisualStyles();
17              Application.SetCompatibleTextRenderingDefault( false );
18               // Application.Run(new ReminderService());
19 
20              HideOnStartupApplicationContext context  =   new  HideOnStartupApplicationContext( new  ReminderService());
21              Application.Run(context);
22             
23          }
24      }
25 
26       ///   <summary>
27       ///  用于实现持续启动时候不显示,本来用Application.Run(new ReminderService()),会强制显示
28       ///   </summary>
29       internal   class  HideOnStartupApplicationContext : ApplicationContext
30      {
31           private  Form mainFormInternal;
32 
33           //  构造函数,主窗体被存储在mainFormInternal
34           public  HideOnStartupApplicationContext(Form mainForm)
35          {
36               this .mainFormInternal  =  mainForm;
37 
38               this .mainFormInternal.Closed  +=   new  EventHandler(mainFormInternal_Closed);
39          }
40 
41           //  当主窗体被关闭时,退出应用程序
42           void  mainFormInternal_Closed( object  sender, EventArgs e)
43          {
44              Application.Exit();
45          }
46      }
47  }

  

程序部署碎碎念  最后,把程序打包,发给My Girl,教她安好,设置开机启动~~~今天收到了30来条短信,还算不错,不过中间有部分短信延迟。。。看来Reminder还是需要进一步加强哈~~

   期间有过一次更新程序,以为得重新做过一个安装包了,后来确定只需要替换两个文件。。。突然又有了想法, 某些软件的更新应该就是这么做的吧:网络上部署一个存放最新程序的空间,软件启动伴随启动一个update进程,比对当前软件版本与网络空间上最新版本的 版本号,如不一致,则通过这个update进程控制,下载,关闭软件程序,替换文件,重启软件程序。。。。。

  接触winform比较少,说来惭愧,之前还没完整的做过打包,部署等工作,这次算是亲身经历了一回。。My Girl环境还没有.Net Framework。。。略过无数波折。。。。亲身体会到软件部署的难易程度对于软 件生命力的影响何其巨大,要不是我要用,估计她【电脑入门水平】无论如何也不会装个还需要装.NET环境的软件,甚至还装不大来呢。。。抛开平台不说,开 发任何软件,使用(特别是上手)的 简易性永远都是值得追求的。


  

 

你可能感兴趣的:(smtp)