很早就想寫寫部落格什麼的,一直都沒實作,現在有點空閑,就随手寫一點,主要介紹下我項目中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函數,就可以正常發送短信了。
溫馨提示:擷取短信中心号需要和相應的廠家聯系,不同廠家擷取短信中心号的方式不同。
希望這篇文章能夠對大家有點作用。如有不當之處的還望能夠和我探讨,另外也希望大家轉載的時候注明出處。