使用C#开发的一个短信收发类

 using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;

namespace SMS_Send
{
    public class SMS
    {


        public SerialPort sp;
        private const string CSCACode = "00";  //无指定短信中心号码,按照CSCA号码
        private const string FO = "11";//FO取值
        private const string TPMR = "00"; //TP-MR取值
        private const string MBLenth = "0D";//手机号码长度为13位
        private const string TAddress = "91";//目标号码地址类型,国际
        private const string QH = "68";//中国的国际区号
        private const string PID = "00"; //IP协议号
        private const string CodeMode = "08";//编码模式 08为Unicode,00为Bit7编码,15为Bit8编码
        private const string Msg_Time = "01";//短信保留有效期

        private string sMsgCenterNumber;
        //短信中心号码

        #region Initialize Drive
        public void IniDrv(string sPort, int nBaud)
        {
            string sBack = "";
            try
            {
                bool bOpen = false;
                bOpen = InitCom(sPort, nBaud);

                if (bOpen)
                {
                    //GET Modem Model                   
                    sBack = WriteAtCommand("AT+CGMI/r");
                    //check drive run status
                    if (sBack.IndexOf("ERROR") < 0 && sBack.Length > 17)
                    {
                        for (int i = 0; i <= 60; i++)
                        {
                            sBack = WriteAtCommand("AT+CMGF=0/r");
                            if (sBack.IndexOf("ERROR") < 0)
                            {
                                break;
                            }
                            else
                            {
                                Thread.Sleep(1000);
                                if (i == 60)
                                {
                                    throw new Exception("Initialize SMS Modem Fail!");
                                }
                            }
                        }
                        WriteAtCommand("AT+CNMI=0,1,0,0,0/r");
                        //设置短信中心号码;
                        GetMsgCenterNumber();
                    }
                    else
                    {
                        throw new Exception("Initialize SMS Modem Fail!");
                    }
                }
            }
            catch (Exception e)
            {
                FreeDrv();
                throw e;
            }
        }
        /// <summary>
        /// 打开COM口的方法
        /// </summary>
        /// <param name="PortName"></param>
        /// <param name="PortNum"></param>
        /// <returns></returns>

        private bool InitCom(string PortName, int PortNum)//初始化建串口类实例
        {
            try
            {
                sp = new SerialPort(PortName, PortNum, Parity.None, 8);
                sp.ReceivedBytesThreshold = 10;
                sp.Handshake = Handshake.RequestToSend;
                sp.Parity = Parity.None;
                sp.ReadTimeout = 600;
                sp.WriteTimeout = 600;
                if (!sp.IsOpen)
                {
                    sp.Open();
                }
                return true;
            }
            catch
            {
                throw new Exception("Serial Port Can't Open!");
            }
        }


        #endregion

        #region Free Drive
        public void FreeDrv()
        {
            if (sp != null)
            {
                sp.Dispose();
                sp.Close();
            }
        }
        #endregion


        #region Send AT command to modem

        /// <summary>
        /// 发关一个 At 命令给设备
        /// </summary>
        /// <param name="sAtCommand">at command </param>
        /// <returns>execute 'AT' command result </returns>
        private string WriteAtCommand(string sAtCommand)
        {
            sp.Write(sAtCommand + "/r");
            Thread.Sleep(1000);
            byte[] buffer = new byte[sp.BytesToRead];
            sp.Read(buffer, 0, buffer.Length);
            return System.Text.Encoding.ASCII.GetString(buffer);
        }
        #endregion

        #region Get Message Center Number
        /// <summary>
        /// Get Message Center Number
        /// </summary>
        /// <returns>Message Center Number </returns>
        public string GetMsgCenterNumber()
        {
            string sBack = WriteAtCommand("AT+CSCA?/r");
            if (sBack.IndexOf("ERROR") < 0)
            {
                sMsgCenterNumber = sBack.Substring(20, 14);
                sBack = WriteAtCommand("AT+CSCA=" + sMsgCenterNumber + ";&W");
            }
            return sMsgCenterNumber;
        }
        #endregion

        #region Send Message
        public bool SendMessage(string sReceieveNo, string sMsgContent)
        {
            string PduData = "";
            sp.DiscardInBuffer();
            sp.DiscardOutBuffer();


            smsDecodedsms mes = new COutgoingMessage(sReceieveNo, sMsgContent);
            mes.MessageEncoding = CMessage.MESSAGE_ENCODING_7BIT;
            mes.ValidityPeriod = 12;
            string smscNumber = "";
            PduData = mes.GetPDU(smscNumber, 0, 0);

            int j = PduData.Length;
            j /= 2;
            j--;
            sp.Write("AT+CMGS=" + j.ToString() + "/r");
            Thread.Sleep(500);
            sp.Write(PduData);
            sp.Write(((char)26).ToString() + "/r");

            return true;

        }
        #endregion

        #region Read Com Port
        public string ReadCom()//返回信息
        {
            try
            {
                byte[] buffer = new byte[sp.BytesToRead];
                sp.Read(buffer, 0, buffer.Length);
                return System.Text.Encoding.ASCII.GetString(buffer);
            }
            catch
            {
                return "Read SMS Fail!";
            }
        }

        #endregion

        #region SMS Message Convert to PDU
        /// <summary>
        /// 函数功能:短信内容编码
        /// 函数名称:smsPDUEncoded(string srvContent)
        /// 参    数:srvContent 要进行转换的短信内容,string类型
        /// 返 回 值:编码后的短信内容,string类型
        /// 函数说明:
        ///          1,采用Big-Endian 字节顺序的 Unicode 格式编码,也就说把高低位的互换在这里完成了
        ///          2,将转换后的短信内容存进字节数组
        ///          3,去掉在进行Unicode格式编码中,两个字节中的"-",例如:00-21,变成0021
        ///          4,将整条短信内容的长度除2,保留两位16进制数
        /// </summary>
        private string smsPDUEncoded(string srvContent)
        {
            Encoding encodingUTF = System.Text.Encoding.BigEndianUnicode;
            string s = null;
            byte[] encodedBytes = encodingUTF.GetBytes(srvContent);
            for (int i = 0; i < encodedBytes.Length; i++)
            {
                s += BitConverter.ToString(encodedBytes, i, 1);
            }
            s = String.Format("{0:X2}{1}", s.Length / 2, s);

            return s;
        }

        /// <summary>
        /// 函数功能:接收短信手机号编码
        /// 函数名称:smsDecodedNumber(string srvNumber)
        /// 参    数:srvCenterNumber 要进行转换的短信中心号,string类型
        /// 返 回 值:编码后的接收短信手机号,string类型
        /// 函数说明:
        ///          1,检查当前接收手机号是否按标准格式书写,不是,就补上“86”
        ///          1,将奇数位和偶数位交换。
        ///          2,短信中心号奇偶数交换后,看看长度是否为偶数,如果不是,最后添加F
        /// </summary>
        private string smsDecodedNumber(string srvNumber)
        {
            string s = null;
            if (!(srvNumber.Substring(0, 3) == "106"))
            {
                if (!(srvNumber.Substring(0, 2) == "86"))
                {
                    srvNumber = String.Format("86{0}", srvNumber);    //检查当前接收手机号是否按标准格式书写,不是,就补上“86”
                }
            }
            int nLength = srvNumber.Length;
            for (int i = 1; i < nLength; i += 2)                //将奇数位和偶数位交换
            {
                s += srvNumber[i];
                s += srvNumber[i - 1];
            }
            if (!(nLength % 2 == 0))                              //是否为偶数,不是就加上F,并对最后一位与加上的F位互换
            {
                s += 'F';
                s += srvNumber[nLength - 1];
            }
            return s;
        }

        /// <summary>
        ///  函数功能:整个短信的编码
        /// 函数名称:smsDecodedsms(string strCenterNumber, string strNumber, string strSMScontent)
        /// 参    数:strCenterNumber 要进行转换的短信中心号,string类型
        ///          strNumber      接收手机号码,string类型
        ///          strSMScontent  短信内容
        /// 返 回 值:完整的短信编码,可以在AT指令中执行,string类型
        /// 函数说明:
        ///          11000D91和000800  在国内,根据PDU编码原则,我们写死在此,详细解释请看我的文章
        /// </summary>
        /// <param name="strCenterNumber">SMS Center Number </param>
        /// <param name="strNumber">Receieve SMS Phone NUmber </param>
        /// <param name="strSMScontent"> SMS Content </param>
        /// <returns> </returns>

        private string smsDecodedsms(string strNumber, string strSMScontent)
        {
            string MBCode = smsDecodedNumber(strNumber);
            string Msg_Data = smsPDUEncoded(strSMScontent);
            if (strNumber.Substring(0, 3) == "106")
            {
                string len = "";
                switch (strNumber.Length)
                {
                    case 13:
                        len = "0D";
                        break;
                    case 14:
                        len = "0E";
                        break;
                    case 15:
                        len = "0F";
                        break;
                }
                return "00" + "11" + "00" + len + "81" + MBCode + "00" + "08" + "01" + Msg_Data;
            }
            else
            {
                return "00" + "11" + "00" + "0D" + "91" + MBCode + "00" + "08" + "01" + Msg_Data;
            }
        }
        #endregion
        #region Delete sms
        public void DeleteSms(string sMsgIndes)
        {
            WriteAtCommand("AT+CMGD =" + sMsgIndes);

        }
        #endregion

        #region Read All Message From SMS Card
        public string ReadAllMsg()
        {
            StringBuilder sb = new StringBuilder();
            sp.Write("AT+CMGL=4 /r");
            Thread.Sleep(300);
            bool bRead = true;
            while (bRead)
            {
                byte[] buffer = new byte[sp.BytesToRead];
                sp.Read(buffer, 0, buffer.Length);
                sb.Append(System.Text.Encoding.ASCII.GetString(buffer));
                Thread.Sleep(300);
                if (buffer.Length <= 0)
                {
                    bRead = false;
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Decode the SMS Message
        /// </summary>
        /// <param name="str">SMS PDU Code </param>
        /// <param name="bDelete">Delete Flag True:Read and Delete False:Read Only </param>
        /// <returns> </returns>
        public string DecodeSMS(string str, bool bDelete)
        {

            int index1 = str.IndexOf("/r/n");
            int index2 = str.IndexOf(":");
            int index3 = str.IndexOf(",");
            string sIndex = str.Substring(index2 + 1, index3 - index2 - 1);
            if (bDelete)
            {
                DeleteSms(sIndex);
            }
            string pdu = str.Substring(index1 + 2);
            if (pdu.Substring(40, 2) == "08")
            {
                //return GetTextFromPdu_UCS2(pdu) + "---发送者:" + GetTeleFromPdu(pdu) + "---接收时间:" + GetTimeFromPdu(pdu);
                return GetTextFromPdu_UCS2(pdu) + " ¦" + GetTeleFromPdu(pdu);
            }
            else if (pdu.Substring(40, 2) == "00")
            {
                //return "内容:" + GetTextFromPdu_7Bit(pdu);
                return GetTextFromPdu_7Bit(pdu).Replace("/0", "") + " ¦" + GetTeleFromPdu(pdu);
            }
            else
            {
                return "";
            }

        }
        #endregion

        #region Read Sms
        public string ReadMsg(string msgIndex)//读取信息
        {
            try
            {
                string str = WriteAtCommand("AT+CMGR =" + msgIndex);

                if (str.Contains("OK"))
                {
                    int index1 = str.IndexOf("/r/n");
                    int index2 = str.IndexOf("/r/n", index1 + 2);
                    int index3 = str.IndexOf("/r/n", index2 + 2);
                    string pdu = str.Substring(index2 + 2, index3 - index2 - 2);
                    if (pdu.Substring(40, 2) == "08")
                    {
                        //return GetTextFromPdu_UCS2(pdu) + "---发送者:" + GetTeleFromPdu(pdu) + "---接收时间:" + GetTimeFromPdu(pdu);
                        return GetTextFromPdu_UCS2(pdu) + " ¦" + GetTeleFromPdu(pdu);
                    }
                    else if (pdu.Substring(40, 2) == "00")
                    {
                        //return "内容:" + GetTextFromPdu_7Bit(pdu);
                        return GetTextFromPdu_7Bit(pdu).Replace("/0", "") + " ¦" + GetTeleFromPdu(pdu);
                    }
                    else
                    {
                        return "";
                    }
                }
                else
                {
                    return "";
                }
            }
            catch
            {
                return "";
            }
        }

        //--------------------------短信解码部分开始-------------------------

        private string GetTextFromPdu_7Bit(string pdu) //解析短信正文函数_7-Bit编码
        {
            string TextInPdu = pdu.Substring(58);//截取PDU串中短信正文部分源码
            string Text = "";
            while (TextInPdu.Length % 14 != 0) //最后一组不满7个成员时补"0"
                TextInPdu += "0";
            char[] a = TextInPdu.ToCharArray(); //将源码存入字符数组 a[]
            string b = "";
            for (int i = 0; i < a.Length; i++) //将源码转为二进制并存入字符串 b
                b += GetBinary(a[i]);
            char[] total = b.ToCharArray(); //将二进制码存入字符数组 total[]
            for (int j = 0; j < total.Length; j += 56) //56位二进制码为一组,循环所有组 
            {
                char[] s = new char[56];
                for (int i = 0; i < 56; i++)  //将一组二进制码拷贝到字符数组 s[]
                    s[i] = total[i + j];
                char[] d = new char[56];
                //-------------------------------------------------------------------------------------
                for (int i = 0; i < 7; i++) //组内解码得到目标二进制码数组 d[]
                    d[i] = s[i + 1];
                for (int k = 1; k <= 6; k++)
                {
                    for (int i = k * 7; i < (k + 1) * 7 - k; i++)
                        d[i] = s[i + (k * 2 + 1)];
                    for (int i = (k + 1) * 7 - k; i < (k + 1) * 7; i++)
                        d[i] = s[i - ((7 - k) * 2 + 1)];
                }
                for (int i = 49; i < 56; i++)
                    d[i] = s[i - 1];
                //-------------------------------------------------------------------------------------
                for (int k = 0; k < 56; k += 7) //组内循环得到目标 ASCII 字符       
                {
                    int ascii_nu = 0;
                    for (int m = 0; m < 7; m++)
                        ascii_nu += Convert.ToInt16(d[k + m].ToString()) * (1 << (6 - m));
                    Text += (char)ascii_nu; //输出 ASCII 码相应字符
                }
            }  // END OF loop j
            return Text;
        }

        //=====================================================================================
        private string GetBinary(char Hex) //16 进制转 2 进制
        {
            int Dec;
            if (Hex >= '0' && Hex <= '9')
                Dec = Convert.ToInt16(Hex - '0');
            else
                Dec = Convert.ToInt16(Hex - 'A') + 10;
            int displayMask = 1 << 3;
            StringBuilder Bin = new StringBuilder();
            for (int i = 0; i < 4; i++)
            {
                //append 0 or 1 depending on result of masking
                Bin.Append((Dec & displayMask) == 0 ? "0" : "1");
                //shift left so that mask will find bit of next digit
                //during next iteration of loop
                Dec <<= 1;
            }
            return Bin.ToString();
        }
        //=====================================================================================

        //=====================================================================================
        private string GetTextFromPdu_UCS2(string pdu) //解析短信正文函数_UCS2编码
        {
            //截取PDU串中短信正文部分源码,读者也可用BitConverter函数实现部分转换

            string TextInPdu = pdu.Substring(58);
            string Text = "";
            char[] d = TextInPdu.ToCharArray();//存入字符数组
            for (int i = 0; i < d.Length; i += 4)
            {
                int unicode_nu = 0;
                for (int m = 0; m < 4; m++) //计算 Unicode 十进制值
                    unicode_nu += HexToDec(d[i + m]) * (1 << ((3 - m) * 4));
                Text += (char)unicode_nu; //输出 Unicode 对应字符
            }
            return Text;//返回短信正文内容

        }
        //=====================================================================================
        private int HexToDec(char Hex) //16 进制转 10 进制
        {
            int Dec;
            if (Hex >= '0' && Hex <= '9')
                Dec = Convert.ToInt16(Hex - '0'); //0-9
            else
                Dec = Convert.ToInt16(Hex - 'A') + 10;// A-F
            return Dec;//返回 10 进制值
        }

        //=====================================================================================
        private string GetTeleFromPdu(string pdu) //解析 TeleNumber 函数
        {
            //截取PDU串中短信发送方电话号码源码
            string TeleInPdu = pdu.Substring(26, 12);
            string Tele = "";
            char[] d = TeleInPdu.ToCharArray();//存入字符数组
            for (int i = 0; i < d.Length; i += 2)//字符两两对调
            {
                Tele += d[i + 1].ToString();
                Tele += d[i].ToString();
            }
            Tele = Tele.Substring(0, 11);//去掉末位"F"
            return Tele;//返回发送方电话号码
        }

        //=====================================================================================
        private string GetTimeFromPdu(string pdu) //解析 DateTime 函数
        {
            //截取PDU串中短信日期时间源码
            string TimeInPdu = pdu.Substring(42, 14);
            string Time = "";
            char[] d = TimeInPdu.ToCharArray();//存入字符数组
            for (int i = 0; i < d.Length; i += 2)//字符两两对调
            {
                Time += d[i + 1].ToString();
                Time += d[i].ToString();
            }
            Time = "20" + Time; //将年份前加 20 形成 4 位格式,以下为日期时间输出格式控制
            Time = Time.Substring(0, 4) + "-" + Time.Substring(4, 2) + "-"
                + Time.Substring(6, 2) + " " + Time.Substring(8, 2) + ":"
                + Time.Substring(10, 2) + ":" + Time.Substring(12, 2);
            return Time; //返回短信日期时间[年-月-日 时:分:秒]
        }
        //--------------------------短信解码部分结束-------------------------
        #endregion
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值