天道酬勤

博观而约取,厚积而薄发!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

c#短信发送软件

Posted on 2010-04-29 16:16  Happy Coding  阅读(847)  评论(0编辑  收藏  举报

这款短信发送软件的模式是通过电脑的串口联接一台短信modem(这里我用的是西门子6688手机),通过发送软件去控制短信modem来发送短信。

   既然需要通过串口来与短信modem进行通讯,就需要一个串口通讯控件,这里我使用了微软的mscomm32.ocx串口通讯控件。具体实现方法是通过对mscomm32.ocx的几个属性设置(串口端口设置、发送数据类型设置、读写缓冲区设置等)来达到串口与短信modem进行通讯的目的,然后对输入的短信息进行编码,把编码后的短信息发送至短信modem,再通过AT指令去控制modem的发送。整个软件由三个程序组成,一是发送主程序,二是短信编码程序,三是串口通讯控件,下面作一一介绍。

一、串口通讯控件

   微软的串行通信控件MSCOMM简化了编程,可以快速的建立通信应用程序。MSComm 控件通过串行端口传输和接收数据,为应用程序提供串行通讯功能。MSComm控件在串口编程时非常方便,程序员不必去花时间去了解较为复杂的API函数。
MSCOMM的属性和事件
MSComm 控件有很多重要的属性,这里只讲本程序应用的几个属性。
1)CommPort:设置并返回通讯端口号,在设计时,可以设置成从 1 到 16 的任何数,必须在打开端口之前设置 CommPort 属性;
2)Settings: 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位,设置的格式为“BBBB,P,D,S”,BBBB 为波特率,P 为奇偶校验,D 为数据位数,S 为停止位数;
3)PortOpen: 设置并返回通讯端口的状态。也可以打开和关闭端口,true表示串口打开;
4)Input: 从接收缓冲区返回和删除字符;
5)Output: 向传输缓冲区写一个字符串;
6)InputMode:设置发送和接收数据的类型,InputModeConstants.comInputModeText表示文本的方式,InputModeConstants.comInputModeBinary表示二进制的方式;
7)InputLen:读取接收缓冲区的字节数,如果为0则表示读取整个缓冲区的数据
8)OutBufferCount:返回发送缓冲区内等待发送的字节数,可通过设置该属性为0来清空缓冲区。
9)InBufferCount:返回接收缓冲区内等待发送的字节数,可通过设置该属性为0来清空缓冲区。

二、短信的编码

   短信息是文本信息,短信modem只支持ASCII格式码的文本信息,ASCII码格式包括英文字母A-Z和数字0-9及一些标点符号等字符,为此对于中文短信息必须通过编码使中文变成ASCII码,短信编码有三种模式:BLOCK MODE、基于AT指令的TEXT MODE和基于AT指令的PDU MODE的编码,西门子6688手机支持PDU MODE的编码,这种编码方式是把短信正文经过16进制编码后发送。PDU的编码又分为7bit编码、8bit编码和16bit编码,7bit编码最多可发送160个字符,8bit编码最多可发送140个字符,而16bit编码最多可发送70个字符,这种编码被用显示Unicode(UCS2)文体信息,可被大多数手机显示,所以这里我采用的是UCS2编码,其最多可发送70个字符,不管是英文还是中文。

   一条短信由三部分组成,一是接收方的手机号码,二是短信中心号码,三是短信内容。在实际的编码过程中,这三部分是分开来进行的,最后再把它们合三为一。

⑴、短信中心号码编码

   首先把短信中心号码的奇数位与偶数位互换,然后看其长度是否为偶数,如果不是,在最后添加F,并对最后一位与F互换位置。接着在号码前加上91,相当于加上一个"+"字符。最后计算编码后的总长度并除以2,并把这个数格式化为二位的16进制数。例如:广州的短信中心号码为8613800200500,编码后为0891683108200005F0,08是91683108200005F0的长度除2,即16/2=8,二位16进制表示就是08。

㈡、接收方手机号码编码

   首先检查当前接收方手机号码的前两位是否有86字样,如果没有就补上86,然后奇偶位互换,最后检查整个长度是否为偶数,如果不是就加上F,并对最后一位与F互换位置,如手机号码为13918765434,编码后为683119785634F4。

㈢、短信内容编码

   首先采用Big-Endian字节顺序的Unicode格式编码,即高低位互换,接着把它存入一个字节数组,然后去掉进行Unicode编码过程中的“-”字符,最后把整条编码好后的短信内容长度除2,并格式化成二位16进制数添加到编码后的短信内容前面。

   例如,短信内容为:你好,HELLO!,编码后为:4F60597DFFOC00480065006C006C006F0021,最后根据国内PDU编码的原则在接收手机号编码前加上11000D91,在短信内容前加上000800,并把以上三部分编码串起来即可。

三、AT指令

   AT指令类似于DOS命令,由命令与一些参数组成,来完成对modem实现某一功能的控制。AT指令有很多个,它的基本格式是AT+操作功能符+回车,我编写的这款短信发送软件实际只使用了两个AT指令,分别是:AT+CSCA?和AT+CMGS,前一个是获取存于手机SIM卡里面的短信中心号码的命令,后面一个是发送一条短信命令。通常向modem发送一个AT指令,modem如果执行完成都会有一个执行结果回送。

四、短信发送软件主程序

   下面是主程序的代码,图1是主程序的运行界面

 

PDUdecoding sms = new PDUdecoding();

MSComm com=new MSComm();

Thread t ,w;

private

{

   xiancheng1();

}

 

void xiancheng1()//连接串口

{

   t= new Thread(new ThreadStart(InitCom));//定义连接线程

   t.Start();//启动线程

}

 

private bool lianjie(string duankou,string botelv)

{

   try

    {

      string dk=duankou.Trim().Substring(3);

      if (com.PortOpen==true)com.PortOpen=false;

      com.CommPort = Convert.ToInt16(dk);//串口号

      com.InputMode =MSCommLib.InputModeConstants.comInputModeText;//传输的数据形式是文本

      com.InputLen=0;//读取整个接收缓冲区内容

      com.Settings = botelv+",N,8,1"; //串口基本参数设置

      com.PortOpen=true;//打开串口

      com.OutBufferCount=0;//清空发送缓冲区        

      com.InBufferCount=0;//清空接收缓冲区

      return true;

    }

catch

   {

      MessageBox.Show("错误:连接参数有错,请重新选择!");

      return false;

    }

}

 

 

void InitCom()

{

    int i;

    if(lianjie(duankou.SelectedItem.ToString(),bote.SelectedItem.ToString()))

      

        string Buffer="";

        string bufy="AT+CSCA?\r";

        for(i=0;i<5;i++)

           

             

            com.Output = bufy; //发送数据到串口发送缓冲区           

            Buffer+=com.Input;//接收串口接收缓冲区的数据

 

               

                   break;

                 }

           }

      if(i>4)

        {

           label5.Text="连接失败,重新连接!!";

         }

      else

        {

           int Num1=Buffer.LastIndexOf("86");

           zhongxinhao.Text =Buffer.Substring(Num1,13);

           label5.Text="连接成功!!";

         }

       }

   else

    {

       label5.Text="连接失败,重新连接!!";

    }

   com.PortOpen=false;

   t.Abort();

}

 

private void button2_Click(object sender, System.EventArgs e)

{

    if (com.PortOpen==true)com.PortOpen=false;

    Application.Exit();

}

 

void fsduanxin()

{

   w= new Thread(new ThreadStart(fs));//定义发送线程

   w.Start();//启动线程

}

 

private void button3_Click(object sender, System.EventArgs e)

{

   fsduanxin();

}

 

void fs()

{

    if(lianjie(duankou.SelectedItem.ToString(),bote.SelectedItem.ToString()))

      { 

        string dhnum=shoujihaoma.Text;

        fsdx(dhnum);//发送短信

        com.PortOpen=false;

        w.Abort();

       }

}

 

void fsdx(string danhuahaoma)//发送短信程序段

{

    int i=0;

    duanxinshoufa.Text="正在发送,稍候";

    string Buffer="";

    string decodedSMS = sms.smsDecodedsms(zhongxinhao.Text,danhuahaoma,neirong.Text);

    string bufy="AT+CMGS="+sms.nLength+"\r";

    for(i=0;i<10;i++)

       {

          com.Output = bufy;

          Thread.Sleep(300);

          Buffer+=com.Input;

          Thread.Sleep(500);

          if( Buffer.Length > 0 && Buffer.EndsWith("> "))//判断AT指令执行的回送结果

             {

                string buf=decodedSMS+"\x01a";

                com.Output = buf;

                Thread.Sleep(1000);

                string chenggong = "发送成功!";

                string Result = String.Format("{0},{1},{2}。\n",danhuahaoma,neirong.Text,chenggong);

                duanxinshoufa.Text += "\r\n"+Result;

                break;

              }

          duanxinshoufa.Text +=".";

       }

 

    if(i>9)

      {

        duanxinshoufa.Text ="发送失败,请重新发送!";

        w.Abort();

       }

}

   在程序中使用了线程控制,目的是协调程序运行与串口通讯之间的同步问题。另外在主程序中使用AT指令时都使用了循环,通过对AT指令执行结果回送的检测,判断AT指令是否被正确地执行,如果未被正确执行,则通过循环控制重发AT指令直至AT指令正确执行为止。

   此程序界面简单易用,我把他放上来给有兴趣的朋友使用(点击这里下载)。使用此程序的注意事项:

1、此程序我只在西门子6688,SL45i手机上成功应用。

2、此程序是在.NET平台上开发的,所以要在你的电脑上安装ms.net.framework1.1,这是一个免费软件,网上有下载。

3、程序中所使用的mscomm32.ocx控件需要注册,注册步骤如下:

   ①、将Mscomm32.ocx,Mscomm32.dep两个文件复制到系统SYSTEM32文件夹中。

   ②、用Windows下的注册工具regsvr32注册该OCX控件,点击“开始”->"运行",再在其中填入 Regsvr32 C:\windows\system32\Mscomm32.ocx。

   ③、在注册表中手工新建一个主键项:先在点击“开始”->"运行",再在其中填入regedit命令打开注册表,找到HKEY_CLASSES_ROOT\Licenses,在其中添加主键:4250E830-6AC2-11cf-8ADB-00AA00C00905 并将内容设置为:kjljvjjjoquqmjjjvpqqkqmqykypoqjquoun。 

 

 

 

 

 

 

 

{

            if(Buffer.IndexOf("86")!=-1)//判断AT指令执行的回送结果

 

 

Thread.Sleep(1000); 
{{ 

 

 

 

 

 

 

 

void button1_Click(object sender, System.EventArgs e)