(SMS)使用短信猫发送短信

//======================================================================
//        《31天学会CRM项目开发》机械工业出版社 版权所有 (C) 2015-2016
//        文件名:Form1.cs
//E:\WGY\C#学习\一套开源的企业业务系统框架Winform\586570 31天学会CRM项目开发pdf+源代码\31天学会CRM项目开发-源代码\003 实例及拓展练习\SMSDemo
//        随书附赠源代码,若转发需保留版权信息。
//        社区支持:http://www.huiyaosoft.com/
//======================================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Collections;
namespace SMSDemo
{
    /*
        TEXT格式只能发送英文和数字,若要发送中文,则必须使用PDU格式。
    */
    public partial class Form1 : Form
    {
        private SerialPort serialPort1 = new SerialPort();

        private StringBuilder builder = new StringBuilder();

        private StringBuilder answer = new StringBuilder();

        private String str = string.Empty;

        private Boolean isLock = false;

        private ArrayList waiteSendMsgList;

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

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //string type = str3.Substring(40, 2);
            //MessageBox.Show(Convert.ToString(14, 16));
            //try
            //{
            //    if (type.Equals("00"))
            //        MessageBox.Show(GetTextFromPdu_7Bit(str3));
            //    else if (type.Equals("08"))
            //        MessageBox.Show(GetTextFromPdu_UCS2(str3));
            //}
            //catch (Exception ex)
            //{
            //    Console.WriteLine(ex.Message);
            //}
            smsc = getPhoneNum("8613800532500");
            waiteSendMsgList = new ArrayList();

            // 取得计算机上所有串口
            string[] ports = SerialPort.GetPortNames();
            Array.Sort(ports);
            this.cbComList.Items.AddRange(ports);
            this.cbComList.SelectedIndex = this.cbComList.Items.Count > 0 ? 0 : -1;
            //初始化SerialPort对象
            serialPort1.NewLine = "\r\n";
            // 确定是否使 Request To Send (RTS) 线有效。一般情况下,由计算机发送 Request To Send 信号到联接的调制解调器,以请示允许发送数据。
            // 当 RTSEnable 设置为 True,端口打开时,Request To Send 线设置为高电平,端口关闭时,设置为低电平。
            // Request To Send 线用在 RTS/CTS 硬件握手。RTSEnable 属性允许手动检测 Request To Send 线以确定其状态。
            serialPort1.RtsEnable = true;

            //添加事件注册
            serialPort1.DataReceived += serialPort1_DataReceived;
        }
        
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
            int n = serialPort1.BytesToRead;
            //声明一个临时数组存储当前来的串口数据
            byte[] buf = new byte[n];
            //读取缓冲数据
            serialPort1.Read(buf, 0, n);
            //清除字符串构造器的内容
            builder = new StringBuilder();
            //因为要访问ui资源,所以需要使用invoke方式同步ui。
            this.Invoke((EventHandler)(delegate
            {
                // 直接按ASCII规则转换成字符串
                string bufStr = Encoding.ASCII.GetString(buf);
                builder.Append(bufStr);
                this.tbInfo.AppendText(bufStr);
                answer.Append(bufStr);
                if (!str.Equals(answer.ToString()))
                {
                    str = answer.ToString();
                    if (str.IndexOf("OK") > -1
                        || str.IndexOf("ERROR") > -1
                        || str.IndexOf("BUSY") > -1
                        || str.IndexOf("NO CARRIER") > -1
                        || str.IndexOf("RING") > -1
                        || str.IndexOf("+CMTI") > -1)//发送AT+CMGF=0指令,若收到这些字符串,说明串口处于空闲状态,可写入数据
                    {
                        // 重置属性
                        this.tbInfo.AppendText("\r\n");
                        this.btnSend.Enabled = true;
                        answer = new StringBuilder();
                        isLock = false;

                        #region 读取短信
                        if (str.IndexOf("+CMTI") > -1) //若收到+CMTI字符表示收到新短信。
                        {
                            isLock = true;
                            serialPort1.ReadExisting();
                            serialPort1.WriteLine("AT+CMGL=0"); //可使用此指令读取新短信。
                        }
                        try
                        {
                            //08 指短信中心号码长度
                            //91指短信中心号码类型
                            string reg = @"\r\n0891(\w+)\r\n";
                            Regex r = new Regex(reg);
                            if (r.IsMatch(str))
                            {
                                string content = r.Match(str).Groups[1].Value.ToString();
                                content = "0891" + content;
                                this.tbInfo.AppendText("来自手机:" + GetTeleFromPdu(content) + "\r\n");
                                this.tbInfo.AppendText("接收时间:" + GetTimeFromPdu(content) + "\r\n");
                                string type = content.Substring(40, 2);
                                if (type.Equals("00"))
                                {
                                    this.tbInfo.AppendText("收到短信:" + GetTextFromPdu_7Bit(content) + "\r\n");
                                }
                                else if (type.Equals("08"))
                                {
                                    this.tbInfo.AppendText("收到短信:" + GetTextFromPdu_UCS2(content) + "\r\n");
                                }
                            }
                            else
                                this.tbInfo.AppendText("\r\n");
                        }
                        catch (Exception ex)
                        {
                            this.tbInfo.AppendText(ex.Message + "\r\n");
                        }
                        #endregion

                        // 发送短信
                        SendMsgBySerialPort();
                        this.tbInfo.Text = this.tbInfo.Text.Replace("\r\n\r\n","\r\n");
                    }
                }
            }));
        }

        private void btnConn_Click(object sender, EventArgs e)
        {
            this.tbInfo.Text = string.Empty;
            answer = new StringBuilder();

            //根据当前串口对象,来判断操作
            if (serialPort1.IsOpen)
            {
                //打开时点击,则关闭串口
                serialPort1.Close();
                this.btnSend.Enabled = false;
                isLock = true;
                this.btnConn.Text = "Open";
                this.tsStatus.Text = "串口已关闭";
            }
            else
            {
                //关闭时点击,则设置好端口,波特率后打开
                serialPort1.PortName = this.cbComList.Text;
                serialPort1.BaudRate = int.Parse(this.tbRate.Text);
                serialPort1.DataBits = 8;                               //数据位 
                serialPort1.Parity = System.IO.Ports.Parity.None;       //校验位 无校验
                serialPort1.StopBits = System.IO.Ports.StopBits.One;    //停止位1位
                serialPort1.ReadBufferSize = 1024;   
                try
                {
                    serialPort1.Open();
                    serialPort1.ReadTimeout = 1000;
                    serialPort1.WriteTimeout = 500;
                    serialPort1.WriteLine("AT+CMGF=0");
                    // serialPort1.WriteLine("AT+CMGD=1,2"); // 删除短信
                    this.btnSend.Enabled = true;
                    isLock = false;
                    this.btnConn.Text = "Close";
                    this.tsStatus.Text = "串口已连接";
                }
                catch (Exception ex)
                {
                    //捕获到异常信息,创建一个新的serialPort1对象,之前的不能用了。
                    serialPort1 = new SerialPort();
                    this.tbInfo.AppendText(ex.Message.ToString()+"\r\n");
                }
            }
            this.btnSend.Enabled = serialPort1.IsOpen;
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (!isLock)//串口未被使用
            {
                isLock = true;
                this.btnSend.Enabled = false;
                serialPort1.ReadExisting();
                serialPort1.WriteLine(this.tbCmd.Text);
            }
        }

        #region send msg
        /// <summary>
        /// 电话号码奇偶位对调
        /// </summary> 发送PDU字符串格式
        /// <param name="num"></param>
        /// <returns></returns>
        public static string getPhoneNum(string num)
        {
            //8613800532500
            if (num.Length == 13)
            {
                num = num + "F"; //加个F补齐偶数长度
                string newnum = string.Empty;
                newnum = num.Substring(1, 1) + num.Substring(0, 1) + num.Substring(3, 1) + num.Substring(2, 1) + num.Substring(5, 1) + num.Substring(4, 1) + num.Substring(7, 1) + num.Substring(6, 1) + num.Substring(9, 1) + num.Substring(8, 1) + num.Substring(11, 1) + num.Substring(10, 1) + num.Substring(13, 1) + num.Substring(12, 1);
                return newnum;
            }
            else if (num.Length == 15)
            {
                num = num + "F";//加个F补齐偶数长度
                string newnum = string.Empty;
                newnum = num.Substring(1, 1) + num.Substring(0, 1) + num.Substring(3, 1) + num.Substring(2, 1) + num.Substring(5, 1) + num.Substring(4, 1) + num.Substring(7, 1) + num.Substring(6, 1) + num.Substring(9, 1) + num.Substring(8, 1) + num.Substring(11, 1) + num.Substring(10, 1) + num.Substring(13, 1) + num.Substring(12, 1) + num.Substring(15, 1) + num.Substring(14, 1);
                return newnum;
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 对字符串加码
        /// </summary>
        /// <param name="str"></param>
        /// <param name="getBytes"></param>
        /// <returns></returns>
        public static string StrToBin(string str)
        {
            str = str.Replace("\u0000", string.Empty);
            byte[] charBin = Encoding.BigEndianUnicode.GetBytes(str);
            string result = string.Empty;
            foreach (byte hexNum in charBin)
            {
                result += hexNum.ToString("X2");
            }
            return result;
        }

        public static string BinToStr(string str)
        {
            string result = string.Empty;
            for (int i = 0; i < str.Length / 2; i++)
            {
                result += (char)short.Parse(str.Substring(i * 2, 2), global::System.Globalization.NumberStyles.HexNumber);
            }
            return result;
        }

        public static string getHex(Int32 l)
        {
            try
            {
                string s = Convert.ToString(l, 16);
                if (s.Length == 1)
                {
                    return "0" + s;
                }
                else
                {
                    return s;
                }
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }

        private void SendMsg(String phoneNum, String content)
        {
            try
            {
                //ATD86811596;拨电话
                //ATH挂电话
                //网通8613090175500,移动8613800544500。注意加上86
                string to = getPhoneNum("86" + phoneNum);//接收号码
                StringBuilder msgBuilder = new StringBuilder();
                foreach (char s in content)
                {
                    msgBuilder.Append(StrToBin(s.ToString()));
                    if (msgBuilder.ToString().Length >= 270)
                    {
                        // 加入短信队列
                        AddToWaiteSendMsgList(smsc, to, msgBuilder.ToString());
                        msgBuilder = new StringBuilder();
                    }
                }
                if (!string.IsNullOrEmpty(msgBuilder.ToString()))
                    AddToWaiteSendMsgList(smsc, to, msgBuilder.ToString());
                this.tbInfo.AppendText("正在发送短信:" + phoneNum + "," + content + "\r\n");
                SendMsgBySerialPort();
            }
            catch (Exception ex)
            {
                this.tbInfo.AppendText(ex.Message + "\r\n");
            }
        }

        private void AddToWaiteSendMsgList(string smsc_, string to, string pduContent)
        {
            // 拼接PDU命令
            int l = pduContent.Length / 2;
            answer = new StringBuilder();
            pduContent = "11000D91" + to + "000800" + getHex(l) + pduContent;
            pduContent = "0891" + smsc_ + pduContent;
            pduContent = pduContent.ToUpper();
            l = (pduContent.Length - 18) / 2;
            waiteSendMsgList.Add("AT+CMGS=" + l.ToString() + "\r" + pduContent);
        }

        private void SendMsgBySerialPort()
        {
            #region 发送短信
            if (waiteSendMsgList.Count > 0)
            {
                isLock = true;
                this.serialPort1.Write(waiteSendMsgList[0].ToString());
                this.serialPort1.Write("\x01A");
                //this.serialPort1.WriteLine(string.Empty);
                //System.Threading.Thread.Sleep(100);
                this.tbInfo.AppendText(string.Format("正在发送……,还有{0}条等待\r\n", (waiteSendMsgList.Count -1)));
                waiteSendMsgList.RemoveAt(0);
            }
            #endregion
        }

        private string GetTextFromPdu_7Bit(string pdu) //解析短信正文函数_7-Bit编码
        {
            string TextInPdu = pdu.Substring(58);//截取PDU串中短信正文部分源码
            string Text = string.Empty;
            while (TextInPdu.Length % 14 != 0) //最后一组不满个成员时补"0" 
                TextInPdu += "0";
            char[] a = TextInPdu.ToCharArray(); //将源码存入字符数组a[] 
            string b = string.Empty;
            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;
        }

        //===================================================================================== 
        /// <summary>
        /// 16进制转成对应二进制字符串 如“1” 转成“0001”
        /// </summary>
        /// <param name="Hex"></param>
        /// <returns></returns>
        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 = string.Empty;
            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 = string.Empty;
            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 = string.Empty;
            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; //返回短信日期时间[年-月-日时:分:秒] 
        }

        public static bool RegexValidate(string regexString, string validateString)
        {
            Regex regex = new Regex(regexString);
            return regex.IsMatch(validateString.Trim());
        }
        #endregion

        private void btnSendMsg_Click(object sender, EventArgs e)
        {
            SendMsg(this.tbPhone.Text, this.tbMsg.Text);
        }


        /// <summary>
        /// 取得字节长度,一个汉字等于2字节
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int GetLength(string str)
        {
            if (str.Length == 0)
                return 0;
            ASCIIEncoding ascii = new ASCIIEncoding();
            int tempLen = 0;
            byte[] s = ascii.GetBytes(str);
            for (int i = 0; i < s.Length; i++)
            {
                if ((int)s[i] == 63)
                    tempLen += 2;
                else
                    tempLen += 1;
            }
            return tempLen;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值