C#下的GSM短信实现

        很早就想写写博客什么的,一直都没实现,现在有点空闲,就随手写一点,主要介绍下我项目中c#下面实现GSM短信功能的代码,该代码主要适用在手机以及pda上。网上的资料零零散散,并且有很多问题,例如特殊字符解析不出来等。下面进入正题吧。

       以下主要讲解的是PDU格式发送短信。

       手机或者短信发送短信,是以串口通过AT指令的方式发送,PDU格式的短信格式为:短信中心号码类型+短信中心号+文件头字节+信息类型+被叫号码长度+被叫号码类型,下面以

       接收的手机号:13715342642
    短信中心号:8613800755000
    短信内容:你好,Hello!

为列,它解析成PDU格式的字符串为:“0891683108705500F011000D91683117352446F2000800124F60597DFF0C00480065006C006C006F0021
       ”08 - 指的是短信中心号的长度,也就是指(91)+( 683108705500F0)的长度
  
  91 - 指的是短信息中心号码类型。91是TON/NPI遵守International/E.164标准,指在号码前需加'+'号;此外还有其它数值,但91最常用。
  
  683108705500F0 - 短信息中心号码。由于位置上略有处理,实际号码应为:8613800731500(字母F是指长度减1)。这需要根据不同的地域作相应的修改。前面的(08)+(91)+( 683108705500F0)实际上就构成了整个短信的一部份,通称短消息中心地址(Address of the SMSC)。
  
     11 - 文件头字节
  
  00 - 信息类型(TP-Message-Reference)
  
  0D - 被叫号码长度
  
     91 - 被叫号码类型
  
  其实在实际处理中,我们通常把11000D91写死在程序中,因为在国内,这些数据都是不会改变的。
  
  683117352446F2 -被叫号码,经过了位移处理,实际号码为"8613715342642"。上面的(00)+(0D)+(91)+ ( 683117352446F2),构成了整个短信的第二部份目的地址(TP-Destination-Address)。
  
  00 - 协议标识TP-PID,这里一般为00
  
  08 - 数据编码方案TP-DCS(TP-Data-Coding-Scheme),采用前面说的USC2(16bit)数据编码
  
  00 - 有效期TP-VP(TP-Valid-Period)
  
  12-长度TP-UDL(TP-User-Data-Length),也就是4F60597DFF0C00480065006C006C的长度 36 / 2 = 18 的十六进 124F60597DFF0C00480065006C006C 006F0021- 这里就是短信内容了,实际内容为:"你好,Hello!"
        知道了理论,下面我们就来了解下C#如何编写

 

public class PduEncodeDecode
    {
        /// <summary>
        ///手机号码转换为pdu模式
         /// </summary>
        /// <param name="MobileNum"></param>
        /// <returns></returns>
        public string telc(string MobileNum)
        {
            int tl;
            string ltem, rtem, ttem;
            int ti;

            ttem = "";
            tl = MobileNum.Trim().Length;
            if (tl != 11 && tl != 13)
            {
                //MessageBox.Show("wrong number:" + MobileNum);
                return "";
            }

            if (tl == 11)  // 11位转换为13位
              {
                tl += 2;
                MobileNum = "86" + MobileNum;
            }

            for (ti = 0; ti < tl; ti += 2)
            {
                ltem = MobileNum.Substring(ti, 1);
                if (ti == tl - 1)
                {
                    rtem = "F";
                }
                else
                {
                    rtem = MobileNum.Substring(ti + 1, 1);
                }

                ttem += rtem + ltem;  //每两位颠倒
            }

            return ttem;
        }

        /// <summary>
        /// Unicode解码函数
         /// </summary>
        /// <param name="smsg"></param>
        /// <returns></returns>
        public string ascg(string smsg)
        {
            string res = "";
            string ls;
            string rs;

            byte[] resByte = System.Text.UnicodeEncoding.Unicode.GetBytes(smsg);
            for (int i = 0; i < resByte.Length; i += 2)
            {
                ls = resByte[i].ToString("X2");
                rs = resByte[i + 1].ToString("X2");
                res = res + rs + ls; //注意这里高低位颠倒
              }
            return res.Trim();
        }

        /// <summary>
        /// 发往发送方短信的PDU编码
        /// </summary>
        /// <param name="CenterNo">短信中心号码</param>
        /// <param name="PhoneNo">接收号码</param>
        /// <param name="Message">短信内容</param>
        /// <returns>返回PDU编码</returns>
        public string GetPduEncode(string CenterNo, string PhoneNo, string Message,out int length)
        {
            string prex = "0891";
            string midx = "11000D91";
            string sufx = "000800";

            string pdu, psmsc, pnum, pmsg;
            string leng;
           //  int length;


            length = (Message.Length) * 2;
            leng = length.ToString("X");

            if (length < 16)
            {
                leng = "0" + leng;
            }

            psmsc =telc(CenterNo.Trim());
            pnum = telc(PhoneNo.Trim());
            pmsg = ascg(Message.Trim());
            pdu = prex + psmsc + midx + pnum + sufx + leng + pmsg;//注意编码组合方式
            return pdu;
        }


        ///   <summary>   
        ///   判断接受的短信是PDU格式还是TEXT格式   
         ///   </summary>   

        public bool IsPDU(string SMS)
        {
            if ((SMS.Substring(40, 2) == "08") | (SMS.Substring(38, 2) == "08") || (SMS.Substring(34, 2) == "08"))
            //if (SMS.IndexOf("08111111")>-1)
                return true;
            else
                return false;
        }

        /// <summary>     
        /// 针对国际91(+)提取短信的发送人电话号码       
         ///   </summary>   
        /// <param name="SMS">要进行转换的整个短信内容</param>
        /// <returns>电话号码 </returns>

        public string GetTelphone(string SMS)
        {
            string tel = SMS.Substring(26, 12);
            string s = "";
            for (int i = 0; i < 11; i += 2)
            {
                s += tel[i + 1];
                s += tel[i];
            }
            s += tel[tel.Length -1];
            return s;
        }

        /// <summary>     
        /// 针对国内A1提取短信的发送人电话号码       
         ///   </summary>   
        /// <param name="SMS">要进行转换的整个短信内容</param>
        /// <returns>电话号码 </returns>

        public string GetTelphoneA1(string SMS)
        {
            string tel = SMS.Substring(24, 12);
            string s = "";
            for (int i = 0; i < 11; i += 2)
            {
                s += tel[i + 1];
                s += tel[i];
            }
            s += tel[tel.Length - 2];
            return s;
        }

     
        /// <summary>
        ///   函数功能:针对国际91(+)提取短信的发送时间          
         /// </summary>
        /// <param name="SMS">SMS:要进行转换的整个短信内容</param>
        /// <returns>发送时间 </returns>
        public string GetDataTime(string SMS)
        {
            string time = SMS.Substring(42, 12);
            string s = "";
            for (int i = 0; i < 11; i += 2)
            {
                s += time[i + 1];
                s += time[i];
            }
            string t = s.Substring(0, 2) + "年" + s.Substring(2, 2) + "月" + s.Substring(4, 2) + "日" + s.Substring(6, 2) + ":" + s.Substring(8, 2) + ":" + s.Substring(10, 2);
            return t;
        }

        /// <summary>
        ///   函数功能:针对国内A1提取短信的发送时间          
         /// </summary>
        /// <param name="SMS">SMS:要进行转换的整个短信内容</param>
        /// <returns>发送时间 </returns>
        public string GetDataTimeA1(string SMS)
        {
            string time = SMS.Substring(40, 12);
            string s = "";
            for (int i = 0; i < 11; i += 2)
            {
                s += time[i + 1];
                s += time[i];
            }
            string t = s.Substring(0, 2) + "年" + s.Substring(2, 2) + "月" + s.Substring(4, 2) + "日" + s.Substring(6, 2) + ":" + s.Substring(8, 2) + ":" + s.Substring(10, 2);
            return t;
        }


        /// <summary>
        /// 函数功能:针对国内A1USC2编码提取短信的内容(PDU)   
        /// </summary>
        /// <param name="SMS">SMS:要进行转换的整个短信内容</param>
        /// <returns>短信内容</returns>
        public string GetContentA1(string SMS)
        {
            string c = "";
            //string len = SMS.Substring(54, 2);
            string len = SMS.Substring(SMS.IndexOf("08111111")+14, 2);
            int length = System.Convert.ToInt16(len, 16);
            length *= 2;
            length = SMS.Length;
            string content = SMS.Substring(56+8, length - 56-8);
            for (int i = 0; i < length; i += 4)
            {
                if (i + 4 <= content.Length)
                {
                    string temp = content.Substring(i, 4);
                    int by = System.Convert.ToInt16(temp, 16);
                    char ascii = (char)by;
                    c += ascii.ToString();
                }
            }
            return c;   

        }

        /// <summary>
        /// 函数功能:针对国际(+91)USC2编码提取短信的内容(PDU)   
        /// </summary>
        /// <param name="SMS">SMS:要进行转换的整个短信内容</param>
        /// <returns>短信内容</returns>
        public string GetContent(string SMS)
        {
            string c = "";
            string len = SMS.Substring(56, 2);
            //string len = SMS.Substring(SMS.IndexOf("08111111") + 16, 2);
            int length = System.Convert.ToInt16(len, 16);
            length *= 2;
            string content = SMS.Substring(58, length);
            for (int i = 0; i < length; i += 4)
            {
                if (i + 4 <= content.Length)
                {
                    string temp = content.Substring(i, 4);
                    int by = System.Convert.ToInt16(temp, 16);
                    char ascii = (char)by;
                    c += ascii.ToString();
                }
            }
            return c;

        }
        /// <summary>
        /// 判断是否是国内A1编码
         /// </summary>
        /// <returns>返回布尔值</returns>
        public bool IsA1TypeNo(string SMS)
        { 
         string str=SMS.Substring(22,2);
         if(str=="A1")
         {
             return true ;
         }
         else
         {
             return false;
         }
        }
    }

 

      以上代码是把要发送的信息编译成PDU格式,下面介绍如何把PDU格式的字符串发送。

     

        /// <summary>
        /// 发送短消息
         /// </summary>
        /// <param name="CenterNo">短信中心号码</param>
        /// <param name="PhoneNo">对方手机号</param>
        /// <param name="Message">发送信息内容</param>
        /// <returns></returns>
        public bool sendMsg(string CenterNo, string PhoneNo, string Message)
        {
            bool isSend = true;

            try
            {

                PduEncodeDecode pdendecode = new PduEncodeDecode();
                int length;
                string SMSPdu = pdendecode.GetPduEncode(CenterNo, PhoneNo, Message, out length);//编码成Pdu串
                   string recievedData = ExecCommand(port, "AT", 600, 100);
                Thread.Sleep(50);
                recievedData = ExecCommand(port, "AT+CMGF=0", 600, 100);
                Thread.Sleep(50);
                String command = "AT+CMGS=" + (15 + length).ToString();
                recievedData = ExecCommand(port, command, 600, 300);
                Thread.Sleep(50);
                string s = new string((char)26, 1);
                command = SMSPdu + s;
                ExecCommand(port, command, 3000, 300); //6 seconds
                Thread.Sleep(100);

                return isSend;
            }
            catch (Exception ex)
            {
                return isSend;
                //throw ex;
            }

        }


      只要先打开串口,然后调用sendMsg函数,就可以正常发送短信了。

      温馨提示:获取短信中心号需要和相应的厂家联系,不同厂家获取短信中心号的方式不同。

      希望这篇文章能够对大家有点作用。如有不当之处的还望能够和我探讨,另外也希望大家转载的时候注明出处。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本程序参考网上某个例程编写而成,已完成发送短信功能。GSM模块为wavecom moden。先点击获取SIM卡信息按钮获取短信中心号码,然后输入手机号,短信内容发送短信。希望对同样初次接触GSM模块的兄弟们有帮助。 以下是本程序开发纪录(包括程序都写得比较不规范,请见谅!) 7.14----------------------------------------------- 开始着手GSM模块的学习和编程。弄了一天的时间,以为是win7下的超级终端有错误,后来才发现是我把波特率弄错了,这个wave moden的默认波特率是115200,而我却设成了一般情况下的9600。这是一个很大的教训,欲速则不达。 7.15----------------------------------------------- 自己用C#编了个简单的GSM与上位机连通判断的模块,目标是从串口发送“AT”给GSM模块,GSM模块能够返回与超级终端上返回得到的信息一致(即AT\n OK)。不过没有完成预期的目标,查阅了一些资料发现有可能出现的错误是发送的AT指令编码没编好。 7.16----------------------------------------------- 实现GSM模块与上位机的连通。比如,从C#界面发送“AT”,能够从串口读取到GSM模块返回的“AT\n OK”信息,其他AT指令亦能实现。 发现了一个小BUG,如果GSM模块上电后即在VS2008上调试,则程序能够顺利运行;但如果上电后在超级终端调试过后,再在VS2008上调试,则不能从C#的小程序上获取GSM模块返回的信息。 实现GSM模块发送短信的功能。可以发送中文\英文短信。在此过程中出现了一个低级失误,没把生成的短信中心号码“+8613000……”前的“+”去掉,导致生成的PDU编码有误,发送失败。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值