GSM MODEM发PUSH/MMS 的具体实现.

本文提供了一种使用 GSM Modem 发送 PUSH 和 MMS 消息的实现方法,包括具体的编码过程及分包处理,并附带了完整的 C# 代码示例。

GSMMODEM发PUSH/MMS的原理请搜索网上的很多文章.这里只提供实现代码.我在原来发SMS的PDULib中加了

两个组装PUSH和MMS通知的方法.然后直接利用发SMS的方法发出去.代码都是调用通过的.不过我用SE的GPRS卡插在本本上调用,无论是通过超级终端直接发AT指令还是用程序都不行,好象最后的结束符26(ctrl+z)发不出去.但用MOTO的手机连接本本,无论超级终端还是程序都很顺利.

项目文件在:http://dl2.youkuaiyun.com/down4/20070712/12214323168.rar

连结串口的JustInIO包文件中定义了CommPort类,PUDLib文件中定义了PDUdecoding类,这两个文件搜索一下可以找到N个下载地址.篇幅原因我不贴了.只把在PDUdecoding中加的两个方法(另有两个辅助方法)贴上来:

private static string getUTF8Text(string str)
{
byte[] buf = Encoding.UTF8.GetBytes(str);
StringBuilder sb = new StringBuilder(buf.Length * 2);
for (int i = 0; i < buf.Length; i++)
{
sb.Append(buf[i].ToString("X2"));
}
return sb.ToString();

}
private static string getAsciiText(string str)
{
byte[] buf = Encoding.ASCII.GetBytes(str);
StringBuilder sb = new StringBuilder(buf.Length * 2);
for (int i = 0; i < buf.Length; i++)
{
sb.Append(buf[i].ToString("X2"));
}
return sb.ToString();

}
private string uintToString(int n)
{
byte[] buf = new byte[8];
int l = 0;
while (n >= 128)
{
byte b = (byte)(n & 0x7F);
n = n >> 7;
buf[l++] = b;
}
buf[l++] = (byte)n;
StringBuilder sb = new StringBuilder();
byte[] retBys = new byte[l];
for (int i = 0; i < l; ++i)
{
retBys[i] = (byte)(buf[l - i - 1] | 0x80);
}
retBys[l - 1] &= 0x7F;
for (int i = 0; i < l; i++)
{
sb.Append(retBys[i].ToString("X2"));
}
return sb.ToString();

}

发送PUSH和MMS通知的DECODE方法:

public string smsEncodePushMessage(string strNumber, string strTitle, string strURL)
{

string[] content = getPushContents(strTitle, strURL);
StringBuilder sb = new StringBuilder();
nLength = "";
for (int i = 00; i < content.Length; i++)
{
string s = String.Format("0051000D91{0}00F5A7{1}{2}", smsDecodedNumber(strNumber), (content[i].Length / 2).ToString("X2"), content[i]);
sb.Append(s);
int len = (s.Length / 2) - 1;//10进制
nLength += len.ToString();
if (i != content.Length - 1)
{
sb.Append(";");
nLength += ";";
}
}
return sb.ToString();
}

public string smsEncodeMMSMessage(string strNumber, string sendNumber, string strTitle, string strURL)
{
string[] content = getMMSContents(sendNumber, strTitle, strURL);
StringBuilder sb = new StringBuilder();
nLength = "";
for (int i = 00; i < content.Length; i++)
{
string s = String.Format("0051000D91{0}00F5A7{1}{2}", smsDecodedNumber(strNumber), (content[i].Length / 2).ToString("X2"), content[i]);
sb.Append(s);
int len = (s.Length / 2) - 1;//10进制
nLength += len.ToString();
if (i != content.Length - 1)
{
sb.Append(";");
nLength += ";";
}
}
return sb.ToString();

}

private string[] getPushContents(string title, string url)
{

string singleHead = "0605040B840000";
string MoreHead = "0B05040B840000000301";

string pud = "01060403AE81EA";
string pushUrlBegin = "02056A0045C6080B03";
string pushTitleBegin = "000103";
string pushEnd = "000101";

StringBuilder content = new StringBuilder();
content.Append(pud);
content.Append(pushUrlBegin);
content.Append(getAsciiText(url));
content.Append(pushTitleBegin);
content.Append(getUTF8Text(title));
content.Append(pushEnd);

string contentStr = content.ToString();

if ((contentStr.Length + singleHead.Length) < 140 * 2)
{
string[] messages = new string[1];
messages[0] = singleHead + contentStr;
return messages;
}
else
{
int packSize = 140 * 2 - MoreHead.Length - 2 * 2;//总包数加当前包数两个字节
int packCount = (contentStr.Length / packSize) + (contentStr.Length % packSize == 0 ? 0 : 1);
string[] messages = new string[packCount];
for (int i = 0; i < packCount; i++)
{
StringBuilder buf = new StringBuilder();
buf.Append(MoreHead);
buf.Append(packCount.ToString("X2"));
buf.Append((i + 1).ToString("X2"));
if (i == (packCount - 1))
buf.Append(contentStr.Substring(i * packSize));
else
buf.Append(contentStr.Substring(i * packSize, packSize));
messages[i] = buf.ToString();
}
return messages;
}
}
private string[] getMMSContents(string sendNumber,string title, string url)
{

string singleHead = "0605040B840000";
string MoreHead = "0B05040B840000000301";

title = getUTF8Text(title);
url = getAsciiText(url);

StringBuilder content = new StringBuilder();

content.Append("25") //Transaction ID
.Append("0622") //type,header-len
.Append(getAsciiText("application/vnd.wap.mms-message"))
.Append("AF84") //X-Wap-Application-ID type=2F (+80),x-wap-application:mms.ua=04 (+80)
.Append("8C82") //Message Type :m-notification.ind
.Append("98"); //X-MMS-Transaction-Id
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1);
int x = (int)(ts.TotalMilliseconds / 1000);
content.Append(getAsciiText(x.ToString()))
.Append("00")
.Append("8D90") //version 1.0
.Append("89"); //From
string from = getAsciiText(sendNumber);
int fromLen = from.Length / 2 + 2;
string strFromLen = fromLen.ToString("X2");
content.Append(strFromLen)
.Append("80") //from begin
.Append(from)
.Append("00")
.Append("96"); //subject
int subLen = title.Length / 2 + 2; //EA,00编码和结束符
content.Append(subLen.ToString("X2"))
.Append("EA")
.Append(title)
.Append("00");
content.Append("8A80"); //Message-Class:Personal
content.Append("8E"); //Message-size
int msgSize = 12345;
string strMsgSize = msgSize.ToString("X4");
int sizeLen = strMsgSize.Length / 2;
content.Append(sizeLen.ToString("X2"))
.Append(strMsgSize)
.Append("88") //有效期
.Append("058103093A80"); //总长度5,相对格式.秒数长度3,093A80为604800秒,一周.
content.Append("83") //X-MMS-Content-Location
.Append(url)
.Append("00");
string contentStr = content.ToString();
if ((contentStr.Length + singleHead.Length) < 140 * 2)
{
string[] messages = new string[1];
messages[0] = singleHead + contentStr;
return messages;
}
else
{
int packSize = 140 * 2 - MoreHead.Length - 2 * 2;//总包数加当前包数两个字节
int packCount = (contentStr.Length / packSize) + (contentStr.Length % packSize == 0 ? 0 : 1);
string[] messages = new string[packCount];
for (int i = 0; i < packCount; i++)
{
StringBuilder buf = new StringBuilder();
buf.Append(MoreHead);
buf.Append(packCount.ToString("X2"));
buf.Append((i + 1).ToString("X2"));
if (i == (packCount - 1))
buf.Append(contentStr.Substring(i * packSize));
else
buf.Append(contentStr.Substring(i * packSize, packSize));
messages[i] = buf.ToString();
}
return messages;
}

注意上面两个私有支持方法因为支持分包所以都返回了字符串数组.两个公开的接口方法对返回的数组进行了重组装.这样在发送时要根据多包的特点多次发送.有了这两个方法.按正常发送SMS的方法就可以发送了:

连接COM口的方法:

private void connect_Click(object sender, EventArgs e)
{
if (this.InitCom("COM7", 9600))
{
this.connect.Enabled = false;
ss_port.Write(Encoding.ASCII.GetBytes("AT+CSCA?/r"));//获取手机短信中心号
bool flag = false;
for (int i = 0; i < retryCount; i++)
{
Thread.Sleep(retryTimeOut);
string readBuffer = Encoding.ASCII.GetString(ss_port.Read(128));
this.log.AppendText(readBuffer + "/r/n");
int start = readBuffer.IndexOf("86");
if (start != -1)
{
this.smsCenter.Text = readBuffer.Substring(start, 13);
flag = true;
break;
}
}
if (flag)
{
ss_port.Write(Encoding.ASCII.GetBytes("AT+CMGF=0/r"));
for (int i = 0; i < retryCount; i++)
{
Thread.Sleep(retryTimeOut);
string readBuffer = Encoding.ASCII.GetString(ss_port.Read(128));
this.log.AppendText(readBuffer + "/r/n");
if (readBuffer.IndexOf("OK") != -1)
{
this.log.AppendText("CMGF:"+readBuffer);
break;
}

}
}

//以下为SE的GC75 GPRS必须加的指令,此卡默认CFUN=0,无论Text还是Pdu都不能发.
ss_port.Write(Encoding.ASCII.GetBytes("AT+CFUN=1/r"));
for (int i = 0; i < retryCount; i++)
{
Thread.Sleep(retryTimeOut);
string readBuffer = Encoding.ASCII.GetString(ss_port.Read(128));
this.log.AppendText(readBuffer + "/r/n");
if (readBuffer.IndexOf("OK") != -1)
{
this.log.AppendText("CFUN:" + readBuffer);
break;
}

}
}
}

发送,根据选择框MODE控制选择的结果发送SMS/PUSH/MMS通知:

private void sendSMS_Click(object sender, EventArgs e)
{

PDUdecoding pud = new PDUdecoding();
string decodedSMS = "";

if (this.mode.SelectedIndex == 0)
{
decodedSMS = pud.smsDecodedsms(this.smsCenter.Text, this.destination.Text, this.content.Text);
}
else if (this.mode.SelectedIndex == 1)
{
decodedSMS = pud.smsEncodePushMessage(this.destination.Text, this.content.Text, this.pushurl.Text.Replace("http://", ""));
}
else if (this.mode.SelectedIndex == 2)
{
decodedSMS = pud.smsEncodeMMSMessage(this.destination.Text, "8888", this.content.Text, this.pushurl.Text);
}
else if (this.mode.SelectedIndex == 3)
{
decodedSMS = pud.smsEncodeBookMarkMessage(this.destination.Text, this.content.Text, this.pushurl.Text);
}
string[] contents = decodedSMS.Split(';');
string[] nLens = pud.nLength.Split(';');
for (int x = 0; x < contents.Length; x++)
{
byte[] buf = Encoding.ASCII.GetBytes(String.Format("AT+CMGS={0}/r", nLens[x]));
Console.WriteLine(decodedSMS);
ss_port.Write(buf);
bool isSucc = false;
string readBuffer = "";
for (int i = 0; i < retryCount; i++)
{
Thread.Sleep(retryTimeOut);
readBuffer += Encoding.ASCII.GetString(ss_port.Read(128));
this.log.AppendText(readBuffer + "/r/n");
if (readBuffer.Length > 0 && readBuffer.EndsWith("> "))
{
isSucc = true;
break;
}


}
if (!isSucc)
{
MessageBox.Show("send cmgs ERROR!");
return;

}
isSucc = false;
byte[] sendbyte = Encoding.ASCII.GetBytes(contents[x]);

ss_port.Write(sendbyte);
ss_port.Write(new byte[] { 0x1A });
readBuffer = "";
int mark = 0;
//因为GC75卡响应内容太多,且分为多行,所以为了通用彩用mark标记响应
//内容中有CMGS和OK的内容.
for (int i = 0; i < retryCount; i++)
{
Thread.Sleep(retryTimeOut);
readBuffer = Encoding.ASCII.GetString(ss_port.Read(128));
this.log.AppendText(readBuffer + "/r/n");
if (readBuffer.IndexOf("CMGS:") != -1) mark++;

if (readBuffer.IndexOf("OK") != -1) mark++;
if(mark == 2)
{
isSucc = true;
break;
}
}
if (!isSucc)
{
MessageBox.Show("ERROR");
return;
}
}
MessageBox.Show("OK");

}

<think>好的,用户需要分析签名日志中的错误,特别是检查McfgGenUtils的pm use_central_security_profile标志是否设置为'0',以及secure-image命令的执行情况和相关路径配置是否正确。我需要一步步来拆解这个问题。 首先,我得明确用户提到的几个关键点:日志中的McfgGenUtils信息、secure-image命令的执行情况,还有路径配置是否正确。用户可能是在处理安全相关的配置或签名过程中遇到了问题,导致需要检查日志来排查错误。 接下来,我应该考虑如何检查这些部分。对于日志中的McfgGenUtils信息,用户需要确认pm use_central_security_profile标志的值是否为'0'。这可能涉及到安全配置是否启用,如果该标志被错误地设置为其他值,可能导致安全策略未按预期应用。因此,用户需要查找日志中是否有相关的行,并确认其值是否正确。 然后是secure-image命令的执行情况。用户需要确认这个命令是否成功执行,是否有报错信息。如果命令执行失败,可能需要检查命令的语法是否正确,或者是否有权限问题。此外,查看命令的输出或错误信息可以快速定位问题。 关于路径配置是否正确,用户需要检查相关的配置文件,比如conf目录下的设置,确保所有路径如common、logs、temp等都正确指向预期的目录。如果路径配置错误,可能导致程序无法找到所需的文件或类库,从而引错误。例如,引用[3]中提到conf目录存放配置文件,logs存放日志,这些路径的正确性至关重要。 还需要考虑权限问题,比如执行secure-image命令的用户是否有足够的权限,或者相关目录的读写权限是否设置正确。引用[2]中提到使用sudo -s来获取root权限,如果命令需要高权限,可能需要以root用户运行。 另外,用户可能没有明确说明具体的日志文件位置,可能需要指导他们如何找到正确的日志文件。通常日志存放在logs目录下,但具体位置可能因配置而异,需要查看conf中的配置确认。 最后,综合这些信息,用户需要逐一检查各个部分,确认配置、命令执行和权限都没有问题。如果所有配置正确但问题依旧存在,可能需要深入分析日志中的其他错误信息,或者检查依赖的类库是否完整,如引用[3]中提到的common目录下的支持类库是否存在或版本正确。</think>### 签名日志错误分析步骤 1. **定位McfgGenUtils标志状态** 在日志中搜索关键词`McfgGenUtils`和`use_central_security_profile`,确认`pm use_central_security_profile`的值是否为`0`。例如: ``` McfgGenUtils: pm use_central_security_profile flag set to '0' ``` 若值为`1`或其他非预期值,需检查安全配置文件中相关参数设置[^3]。 2. **检查`secure-image`命令执行状态** - 在日志中查找`secure-image`命令执行记录,确认是否存在`success`或`failure`标记。 - 若命令执行失败,需检查以下内容: - **权限问题**:是否以root用户或拥有足够权限的用户执行(参考`sudo -s`提升权限[^2])。 - **路径配置**:确认命令所在路径是否包含在环境变量`PATH`中,或使用绝对路径执行(如`/opt/security/bin/secure-image`)。 3. **验证相关路径配置** - 检查配置文件(通常在`conf`目录[^3])中定义的路径是否有效: - 安全策略文件路径(如`security_profile.xml`) - 临时文件目录(`temp`)和日志目录(`logs`)的读写权限 - 示例配置错误: ``` ERROR: Cannot access /var/security/cache/secure-image.cache ``` 可能原因为目录不存在或权限不足。 4. **依赖项与类库验证** - 确认`common`目录下的支持类库(如加密模块)是否存在且版本匹配[^3]。 - 使用`ldd`或`java -verbose`命令检查动态链接库或JAR包的加载情况。 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值