|
长短信是有规约的,协议头部分如果是0x40以下,则说明是普通短信,如果是0x40以上,则是长短信,然后在短信内容部分,有六个字节分别定义短信唯一标识以及该短信是第几条,所以长短信发送时每条实际为67个汉字。手机接收到之后,都会按照标准规约自动组合为一条短信,而不是显示多条。
我做了一个AT指令操作wavecom短信收发设备的类,可以接收和发送超长短信,并且接收到的短信会直接通知电脑。
超长短信:短信内容超过70个汉字,提交给网关时候需要分成多条,但是用户手机接收时候是一条(sp角度,手机发送长短信概念一样)。
在cmpp协议里,CMPP-_SUBMIT消息定义中有相应的参数配置:
TP_udhi :0代表内容体里不含有协议头信息 1代表内容含有协议头信息(长短信,push短信等都是在内容体上含有头内容的)当设置内容体包含协议头,需要根据协议写入相应的信息,长短信协议头有两种:
6位协议头格式:05 00 03 XX MM NN
byte 1 : 05, 表示剩余协议头的长度
byte 2 : 00, 这个值在GSM 03.40规范9.2.3.24.1中规定,表示随后的这批超长短信的标识位长度为1(格式中的XX值)。
byte 3 : 03, 这个值表示剩下短信标识的长度
byte 4 : XX,这批短信的唯一标志(被拆分的多条短信,此值必需一致),事实上,SME(手机或者SP)把消息合并完之后,就重新记录,所以这个标志是否唯
一并不是很 重要。
byte 5 : MM, 这批短信的数量。如果一个超长短信总共5条,这里的值就是5。
byte 6 : NN, 这批短信的数量。如果当前短信是这批短信中的第一条的值是1,第二条的值是2。
例如:05 00 03 39 02 01
7位的协议头格式:06 08 04 XX XX MM NN
byte 1 : 06, 表示剩余协议头的长度
byte 2 : 08, 这个值在GSM 03.40规范9.2.3.24.1中规定,表示随后的这批超长短信的标识位长度为2(格式中的XX值)。
byte 3 : 04, 这个值表示剩下短信标识的长度
byte 4-5 : XX XX,这批短信的唯一标志,事实上,SME(手机或者SP)把消息合并完之后,就重新记录,所以这个标志是否唯一并不是很重要。
byte 6 : MM, 这批短信的数量。如果一个超长短信总共5条,这里的值就是5。
byte 7 : NN, 这批短信的数量。如果当前短信是这批短信中的第一条的值是1,第二条的值是2。
例如:06 08 04 00 39 02 01
到此,长短信的发送设置基本完成,但是有一点要注意:Src_Id 协议里这个字段在一条长短信中必须要一样,不然手机会解析成三条,
并三条都 是错误短信。
对于sp来说,长短信上行,按照协议反过来解析:
1byte[] contentBytes = msg.getMsgContent();
2int headLen = contentBytes[0]; // 内容头的长度
3// 超长短信总条数
4int pk_total = contentBytes[headLen - 1];
5// 超长短信第几条
6int pk_num = contentBytes[headLen];
7// 超长短信序号
8byte serial = contentBytes[headLen - 2];
- class DuanXin
- {
- public string phnum;
- public string message;
- public DuanXin()
- {
- }
- public DuanXin(string ph, string msg)
- {
- phnum = ph;
- message = msg;
- }
- }
- class CDuanXin
- {
- public byte biaozhi;
- public byte tiaoshu;
- public byte dqtiaoshu;
- public string dianhua;
- public string msg;
- public DateTime datetime;
- public CDuanXin(byte bz, byte ts, byte dqts, string dh, string mg, DateTime dt)
- {
- biaozhi = bz;
- tiaoshu = ts;
- dqtiaoshu = dqts;
- dianhua = dh;
- msg = mg;
- datetime = dt;
- }
- }
- public class WaveComMsg
- {
- public int Port;
- public int error;
- readonly string zhongzhi = new string((char)26, 1);
- const string head = "00";
- const string quyu = "000D9168";
- const string bianma = "000801";
- const string shujutou = "050003";
- const string ddx = "11";
- const string cdx = "55";
- StringBuilder fszifu = new StringBuilder(350);
- Queue<DuanXin> duanxins = new Queue<DuanXin>(60);
- Object listobj = new Object();
- List<string> items = new List<string>(8);
- public Action<int, string, string, int> Fsjieguo = null;
- public Action<string, string, DateTime> RcvMsg = null;
- public Action DuQu = null;
- bool kongxian = true;
- bool duqu = true;
- Action<DuanXin> Sendmsg = null;
- Random rd = new Random();
- SerialPort sp = null;
- List<CDuanXin> recvcd = new List<CDuanXin>(20);
- public WaveComMsg(int port)
- {
- Port = port;
- sp = new SerialPort("COM"+port);
- sp.RtsEnable = true;
- sp.DtrEnable = true;
- DuQu = ksduqu;
- sp.Open();
- Sendmsg = sendmessage;
- }
- public bool Chushihua()
- {
- string ss = string.Empty;
- try
- {
- sp.Write("AT+CMGF=0" + "\r");
- while (true)
- {
- ss = sp.ReadLine();
- if (ss.Contains("OK"))
- break;
- else if (ss.Contains("ERROR"))
- return false;
- }
- }
- catch
- {
- return false;
- }
- try
- {
- sp.Write("AT+CNMI=2,2,0,0,1" + "\r");
- while (true)
- {
- ss = sp.ReadLine();
- if (ss.Contains("OK"))
- {
- sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
- return true;
- }
- else if (ss.Contains("ERROR"))
- return false;
- }
- }
- catch
- {
- return false;
- }
- }
- public void DoWork(string phnumber, string msg)
- {
- DuanXin dx = new DuanXin(phnumber, msg);
- bool busy = false;
- lock (listobj)
- {
- if (duanxins.Count > 0)
- busy = true;
- duanxins.Enqueue(dx);
- }
- if (!busy)
- Sendmsg.BeginInvoke(dx, null, null);
- }
- void sendmessage(DuanXin dx)
- {
- byte[] msgs = Encoding.BigEndianUnicode.GetBytes(dx.message);
- if (dx.message.Length <= 70)
- {
- fszifu.Append(head);
- fszifu.Append(ddx);
- fszifu.Append(quyu);
- fszifu.Append(phonedecode(dx.phnum));
- fszifu.Append(bianma);
- fszifu.Append(Convert.ToString((dx.message.Length) * 2, 16).PadLeft(2, '0'));
- for (int i = 0; i < msgs.Length; i++)
- fszifu.Append(Convert.ToString(msgs[i], 16).PadLeft(2, '0'));
- fszifu.Append(zhongzhi);
- items.Add(fszifu.ToString());
- fszifu.Clear();
- }
- else
- {
- string h = Convert.ToString(rd.Next(1, 127), 16);
- int lnum = dx.message.Length / 67 + 1;
- for (int i = 0; i < lnum; i++)
- {
- int sjl = i + 1 == lnum ? msgs.Length % 134 + 6 : 140;
- fszifu.Append(head);
- fszifu.Append(cdx);
- fszifu.Append(quyu);
- fszifu.Append(phonedecode(dx.phnum));
- fszifu.Append(bianma);
- fszifu.Append(Convert.ToString(sjl, 16).PadLeft(2, '0'));
- fszifu.Append(shujutou);
- fszifu.Append(h.PadLeft(2, '0'));
- fszifu.Append(Convert.ToString(lnum, 16).PadLeft(2, '0'));
- fszifu.Append(Convert.ToString(i + 1, 16).PadLeft(2, '0'));
- for (int x = 0; x < sjl - 6; x++)
- fszifu.Append(Convert.ToString(msgs[i * 134 + x], 16).PadLeft(2, '0'));
- fszifu.Append(zhongzhi);
- items.Add(fszifu.ToString());
- fszifu.Clear();
- }
- }
- string ss;
- int success = 0;
- kongxian = false;
- for (int m = 0; m < items.Count; m++)
- {
- try
- {
- sp.Write("AT+CMGS=" + (items[m].Length / 2 - 1).ToString().PadLeft(3, '0') + "\r");
- sp.Write(items[m]);
- while (true)
- {
- ss = sp.ReadLine();
- if (ss.StartsWith("0891"))
- readmsg(ref ss);
- else if (ss.Contains("OK"))
- {
- success = 1;
- break;
- }
- else if (ss.Contains("ERROR"))
- {
- success = 0;
- break;
- }
- }
- }
- catch
- {
- success = 0;
- }
- }
- kongxian = true;
- if (success == 0)
- error++;
- if (Fsjieguo != null)
- Fsjieguo.BeginInvoke(Port, dx.phnum, dx.message, success, null, null);
- items.Clear();
- bool busy = false;
- lock (listobj)
- {
- duanxins.Dequeue();
- if (duanxins.Count > 0)
- busy = true;
- }
- if (busy)
- Sendmsg.BeginInvoke(duanxins.Peek(), null, null);
- }
- unsafe string phonedecode(string ph)
- {
- int x = ph.Length % 2 == 0 ? ph.Length : ph.Length + 1;
- char* ca = stackalloc char[x];
- for (int i = 0; i < x; i++)
- if (i % 2 == 0)
- *(ca + i) = (i + 1) == ph.Length ? 'F' : ph[i + 1];
- else
- *(ca + i) = ph[i - 1];
- return new string(ca, 0, x);
- }
- unsafe string phoneencode(string ph)
- {
- int x = ph.Length;
- char* ca = stackalloc char[x];
- for (int i = 0; i < x; i++)
- if (i % 2 == 0)
- *(ca + i) = ph[i + 1];
- else
- *(ca + i) = ph[i - 1];
- if (*(ca + x - 1) == 'F')
- x--;
- return new string(ca, 0, x);
- }
- unsafe DateTime fsshijian(string sj)
- {
- DateTime dt = new DateTime();
- if (sj.Length == 10)
- {
- char* ca = stackalloc char[16];
- ca[0] = '2';
- ca[1] = '0';
- ca[2] = sj[1];
- ca[3] = sj[0];
- ca[4] = '/';
- ca[5] = sj[3];
- ca[6] = sj[2];
- ca[7] = '/';
- ca[8] = sj[5];
- ca[9] = sj[4];
- ca[10] = ' ';
- ca[11] = sj[7];
- ca[12] = sj[6];
- ca[13] = ':';
- ca[14] = sj[9];
- ca[15] = sj[8];
- DateTime.TryParse(new string(ca, 0, 16), out dt);
- }
- return dt;
- }
- unsafe void ksduqu()
- {
- bool ydx = false;
- string s = string.Empty;
- while (true)
- {
- try
- {
- s = sp.ReadLine();
- }
- catch
- {
- ydx = false;
- break;
- }
- if (s.StartsWith("0891"))
- {
- ydx = true;
- break;
- }
- }
- duqu = true;
- if (ydx)
- readmsg(ref s);
- }
复制代码
- void readmsg(ref string s)
- {
- s = s.Trim();
- string mmsg = string.Empty;
- int cd = Convert.ToInt32(s.Substring(18, 2), 16);
- int hmcd = Convert.ToInt32(s.Substring(20, 2), 16);
- if (hmcd % 2 == 1)
- hmcd++;
- string phonum = phoneencode(s.Substring(24, hmcd));
- string bm = s.Substring(24 + hmcd, 4);
- DateTime fssj = fsshijian(s.Substring(28 + hmcd, 10));
- int len = Convert.ToByte(s.Substring(42 + hmcd, 2), 16);
- if (cd < 64)
- {
- byte[] b = new byte[len];
- if (bm == "0000")//text
- {
- byte y = 0;
- int l = 0;
- for (int t = 0; t < len; t++)
- {
- if (t % 8 == 7)
- {
- l++;
- b[t] = y;
- y = 0;
- }
- else
- {
- byte x = Convert.ToByte(s.Substring(2 * (t - l) + 44 + hmcd, 2), 16);
- b[t] = (byte)((((byte)(x << ((t - l) % 7) + 1)) >> 1) + y);
- y = (byte)(x >> (7 - ((t - l) % 7)));
- }
- }
- mmsg = Encoding.ASCII.GetString(b);
- }
- else if (bm == "0008")//tpdu
- {
- for (int i = 0; i < len; i++)
- b[i] = Convert.ToByte(s.Substring(44 + hmcd + i * 2, 2), 16);
- mmsg = Encoding.BigEndianUnicode.GetString(b);
- }
- if (RcvMsg != null)
- RcvMsg.BeginInvoke(phonum, mmsg, fssj, null, null);
- }
- else
- {
- byte[] b = new byte[len];
- if (bm == "0000")//text
- {
- byte y = 0;
- int l = 0;
- for (int t = 0; t < len; t++)
- {
- if (t % 8 == 7)
- {
- l++;
- b[t] = y;
- y = 0;
- }
- else
- {
- byte x = Convert.ToByte(s.Substring(2 * (t - l) + 44 + hmcd, 2), 16);
- b[t] = (byte)((((byte)(x << ((t - l) % 7) + 1)) >> 1) + y);
- y = (byte)(x >> (7 - ((t - l) % 7)));
- }
- }
- mmsg = Encoding.ASCII.GetString(b, 7, len - 7);
- }
- else if (bm == "0008")//tpdu
- {
- for (int i = 0; i < len - 6; i++)
- b[i] = Convert.ToByte(s.Substring(56 + hmcd + i * 2, 2), 16);
- mmsg = Encoding.BigEndianUnicode.GetString(b, 0, len - 6);
- }
- byte bz = Convert.ToByte(s.Substring(50 + hmcd, 2), 16);
- byte ts = Convert.ToByte(s.Substring(52 + hmcd, 2), 16);
- byte dqts = Convert.ToByte(s.Substring(54 + hmcd, 2), 16);
- recvcd.Add(new CDuanXin(bz, ts, dqts, phonum, mmsg, DateTime.Now));
- var cx = (from c in recvcd where c.biaozhi == bz && c.dianhua == phonum orderby c.dqtiaoshu select c).Distinct();
- if (cx.Count() == ts)
- {
- string hjmsg = null;
- foreach (var m in cx)
- {
- hjmsg += m.msg;
- recvcd.Remove(m);
- }
- if (RcvMsg != null)
- RcvMsg.BeginInvoke(phonum, hjmsg, fssj, null, null);
- }
- var ccx = from c in recvcd where (DateTime.Now - c.datetime).Minutes > 30 select c;
- foreach (var n in ccx)
- recvcd.Remove(n);
- }
- }
- void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
- {
- if (kongxian)
- {
- if (duqu)
- {
- duqu = false;
- DuQu.BeginInvoke(null, null);
- }
- }
- }
- public void release()
- {
- sp.Close();
- }
- }
复制代码
|
|