很早就想写写博客什么的,一直都没实现,现在有点空闲,就随手写一点,主要介绍下我项目中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函数,就可以正常发送短信了。
温馨提示:获取短信中心号需要和相应的厂家联系,不同厂家获取短信中心号的方式不同。
希望这篇文章能够对大家有点作用。如有不当之处的还望能够和我探讨,另外也希望大家转载的时候注明出处。