短信报警
有两个原因要求我们的软件工程师及时知道我们的系统的任何部分工作异常: 1. 我们的系统24小时运行,每一个错误都会直接导致损失;2.我们的系统更新太快,没有完整的测试流程,难免会有些问题。
报警检查都不是从技术角度检查的, 而是从业务角度检查,比如订单下载是否正常,我们不是通过检查下载工具是否正常来确定的,而是通过检查下载结果确定的。另外,作为辅助,不是很紧急的异常,我们会用邮件报出来。
先看看AT 指令(转自 http://www.cnblogs.com/top5/archive/2012/04/17/2453924.html, 谢谢与时俱进的分享)
一 . 一 般 命 令 1.AT+CGMI 给出模块厂商的标识。 2.AT+CGMM 获得模块标识。这个命令用来得到支持的频带(GSM 900,DCS 1800 或PCS 1900)。当 模块有多频带时,回应可能是不同频带的结合。 3.AT+CGMR 获得模块的软件版本。 4.AT+CGSN 获得 GSM 模块的 IMEI(国际移动设备标识)序列号。 5.AT+CSCS 选择TE 特征设定。这个命令报告TE 用的是哪个状态设定上的 ME。 ME于是可以转换每一个输入的或显示的字母。这个是用来发送.读取或者撰写短信。 6.AT+WPCS 设定电话簿状态。这个特殊的命令报告通过 TE 电话簿所用的状态的 ME。 ME于是可以转换每一个输入的或者显示的字符串字母。这个用来读或者写电话簿的入口。 7.AT+CIMI 获得 IMSI。这命令用来读取或者识别 SIM 卡的IMSI (国际移动签署者标识)。 在读取 IMSI 之前应该先输入 PIN(如果需要 PIN 的话)码。 8.AT+CCID 获得 SIM 卡的标识。这个命令使模块读取 SIM卡上的 EF-CCID 文件。 9.AT+GCAP 获得能力表。(支持的功能) 10.A/ 重复上次命令。只有 A/ 命令不能重复。这命令重复前一个执行的命令。 11.AT+CPOF 关机。这个特殊的命令停止 GSM 软件堆栈和硬件层。命令 AT+CFUN=0 的功能 与+CPOF 相同。 12.AT+CFUN 设定电话机能。这个命令选择移动站点的机能水平。 13.AT+CPAS 返回移动设备的活动状态。 14.AT+CMEE 报告移动设备的错误。这个命令决定是否允许输出错误代码“+CME ERROR:<xxx>” 或者“+CMSERROR:<xxx>”代替简单的“ERROR” 。 15.AT+CKPD 小键盘控制。仿真 ME小键盘执行命令。 16.AT+CCLK 时钟管理。这个命令用来设置或者获得 ME真实时钟的当前日期和时间。 17.AT+CALA 警报管理。这个命令用来设定在 ME 中的警报日期/时间。(闹铃) 18.AT+CRMP 铃声旋律播放。这个命令在模块的蜂鸣器上播放一段旋律。有两种旋律可用:语音来电 及数据或传真呼叫旋律和到来短信声音。 19.AT+CRSL 设定或获得到来的电话铃声的声音级别。 二 . 呼 叫 控 制 命 令 1.ATD 拨号命令。这个命令用来设置通话.数据或传真呼叫。 2.ATH 挂机命令。 3.ATA 接电话。 4.AT+CEER 扩展错误报告。这个命令给出当上一次通话设置失败后中断通话的原因。 5.AT+VTD 给用户提供应用 GSM 网络发送 DTMF(双音多频)双音频。这个命令用来定义双音 频的长度(默认值是 300 毫秒)。 6.AT+VTS 给用户提供应用 GSM 网络发送 DTMF 双音频。这个命令允许传送双音频。 7.ATDL 重拨上次电话号码。 8.AT%Dn 数据终端就绪(DTR)时自动拨号。 9.ATS0 自动应答。 10.AT+CICB 来电信差。 11.AT+CSNS 单一编号方案。 12.AT+VGR,AT+VGT 增益控制。这个命令应用于调节喇叭的接收增益和麦克风的传输增益。 13.AT+CMUT 麦克风静音控制。 14.AT+SPEAKER 喇叭/麦克风选择。这个特殊命令用来选择喇叭和麦克风。 Tech-Link T&E Limited 15.AT+ECHO 回音取消。 16.AT+SIDET 侧音修正。 17.AT+VIP 初始化声音参数。 18.AT+DUI 用附加的用户信息拨号。 19.AT+HUI 用附加的用户信息挂机。 20.AT+RUI 接收附加用户信息。 三 .网 络 服 务 命 令 1.AT+CSQ 信号质量。 2.AT+COPS 服务商选择。 3.AT+CREG 网络注册。获得手机的注册状态。 4.AT+WOPN 读取操作员名字。 5.AT+CPOL 优先操作员列表。 四 . 安 全 命 令 1.AT+CPIN 输入 PIN。 2.AT+CPIN2 输入 PIN2。 3.AT+CPINC PIN 的剩余的尝试号码。 4.AT+CLCK 设备锁。 5.AT+CPWD 改变密码。 五 . 电 话 簿 命 令 1.AT+CPBS 选择电话簿记忆存储。 2.AT+CPBR 读取电话簿表目。 3.AT+CPBF 查找电话簿表目。 4.AT+CPBW 写电话簿表目。 5.AT+CPBP 电话簿电话查询。 6.AT+CPBN 电话簿移动动作。这个特殊命令使电话簿中的条目前移或后移(按字母顺序) 7.AT+CNUM 签署者号码。 8.AT+WAIP 防止在下一次重起时初始化所有的电话簿。 9.AT+WDCP 删除呼叫电话号码。 10.AT+CSVM 设置语音邮件号码。 六 . 短 消 息 命 令 1.AT+CSMS 选择消息服务。支持的服务有 GSM-MO.SMS-MT.SMS-CB。 2.AT+CNMA 新信息确认应答。 3.AT+CPMS 优先信息存储。这个命令定义用来读写信息的存储区域。 4.AT+CMGF 优先信息格式。执行格式有 TEXT 方式和 PDU 方式。 5.AT+CSAS 保存设置。保存+CSAS 和+CSMP 的参数。 6.AT+CRES 恢复设置。 7.AT+CSDH 显示文本方式的参数。 8.AT+CNMI 新信息指示。这个命令选择如何从网络上接收短信息。 9.AT+CMGR 读短信。信息从+CPMS 命令设定的存储器读取。 10.AT+CMGL 列出存储的信息。 11.AT+CMGS 发送信息。 12.AT+CMGW 写短信息并存储。 Tech-Link T&E Limited 13.AT+CMSS 从存储器中发送信息。 14.AT+CSMP 设置文本模式的参数。 15.AT+CMGD 删除短信息。删除一个或多个短信息。 16.AT+CSCA 短信服务中心地址。 17.AT+CSCB 选择单元广播信息类型。 18.AT+WCBM 单元广播信息标识。 19.AT+WMSC 信息状态(是否读过.是否发送等等)修正。 20.AT+WMGO 信息覆盖写入。 21.AT+WUSS 不改变 SMS 状态。在执行+CMGR 或+CMGL 后仍保持 UNREAD。 七 . 追 加 服 务 命 令 1.AT+CCFC 呼叫继续。 2.AT+CLCK 呼叫禁止。 3.AT+CPWD 改变追加服务密码。 4.AT+CCWA 呼叫等待。 5.AT+CLIR 呼叫线确认限制。 6.AT+CLIP 呼叫线确认陈述。 7.AT+COLP 联络线确认陈述。 8.AT+CAOC 费用报告。 9.AT+CACM 累计呼叫计量。 10.AT+CAMM 累计呼叫计量最大值。 11.AT+CPUC 单价和货币表。 12.AT+CHLD 呼叫相关的追加服务。 13.AT+CLCC 列出当前的呼叫。 14.AT+CSSN 追加服务通知。 15.AT+CUSD 无组织的追加服务数据。 16.AT+CCUG 关闭的用户组。 八 . 数 据 命 令 1.AT+CBST 信差类型选择。 2.AT+FCLASS 选择模式。这个命令把模块设置成数据或传真操作的特殊模式。 3.AT+CR 服务报告控制。这个命令允许更为详细的服务报告。 4.AT+CRC 划分的结果代码。这个命令在呼叫到来时允许更为详细的铃声指示。 5.AT+ILRR 本地 DTE-DCE 速率报告。 6.AT+CRLP 无线电通信线路协议参数。 7.AT+DOPT 其他无线电通信线路参数。 8.AT%C 数据压缩选择。 9.AT+DS 是否允许 V42 二度数据压缩。 10.AT+DR 是否报告 V42 二度数据压缩。 11.AT/N 数据纠错选择。 九 . 传 真 命 令 1.AT+FTM 传送速率。 2.AT+FRM 接收速率 3.AT+FTH 用 HDLC协议设置传真传送速率。 4.AT+FRH 用 HDLC协议设置传真接收速率。 Tech-Link T&E Limited 5.AT+FTS 停止特定时期的传送并等待。 6.AT+FRS 接收沉默。 十 . 第 二 类 传 真 命 令 1.AT+FDT 传送数据。 2.AT+FDR 接收数据。 3.AT+FET 传送页标点。 4.AT+FPTS 页转换状态参数。 5.AT+FK 终止会议。 6.AT+FBOR 页转换字节顺序。 7.AT+FBUF 缓冲大小报告。 8.AT+FCQ 控制拷贝质量检验。 9.AT+FCR 控制接收传真的能力。 10.AT+FDIS 当前会议参数。 11.AT+FDCC 设置 DCE 功能参数。 12.AT+FLID 定义本地 ID 串。 13.AT+FPHCTO 页转换超时参数。 十 一 .V25-V25 命 令 1.AT+IPR 确定 DTE 速率。 2.AT+ICF 确定 DTE-DCE 特征结构。 3.AT+IFC 控制 DTE-DCE 本地流量。 4.AT&C 设置 DCD(数据携带检测)信号。 5.AT&D 设置 DTR(数据终端就绪)信号。 6.AT&S 设置 DST(数据设置就绪)信号。 7.ATV 决定 DCE 响应格式。 8.ATZ 恢复为缺省设置。 9.AT&W 保存设置。 10.ATE 决定是否回显字符。 11.AT&F 回到出厂时的设定。 12.AT&V 显示模块设置情况。 13.AT+WMUX 数据/命令多路复用。 十 二 .特 殊 AT 命 令 1.AT+CCED 小区环境描述。 2.AT+WIND 一般指示。 3.AT+ADC 模拟数字转换度量。 4.AT+CMER 移动设备事件报告。这个命令决定是否允许在键按下时是否主动发送结果代码。 5.AT+WLPR 读取的语言编码。 6.AT+WLPW 写的语言编码。 7.AT+WIOR 读取 GPIO 值。 8.AT+WIOW 写 GPIO 值。 9.AT+WIOM 输入/输出口管理。 10.AT+WTONE 播放旋律。 11.AT+WDTMF 播放 DTMF 旋律。 12.AT+WDWL 进入软件下载模式。 Tech-Link T&E Limited 13.AT+WVR 配置信差的声音速率。 14.AT+WDR 配置数据速率 15.AT+WHWV 显示硬件的版本。 16.AT+WDOP 显示产品的出厂日期。 17.AT+WSVG 声音增益选择。 18.AT+WSTR 返回指定状态的状态。 19.AT+WSCAN 扫描收到的信号强度。 20.AT+WRIM 设置或返回铃声指示模式 21.AT+W32K 是否允许 32kHz 省电方式。 22.AT+WCDM 改变缺省旋律。 23.AT+WSSW 显示内部软件版本。 24.AT+WCCS 编辑或显示订制性质设置表。 25.AT+WLCK 允许在特定的操作符上个性化 ME。 26.AT+CPHS 设置 CPHS 命令。 27.AT+WBCM 电池充电管理。 28.AT+WFM 特性管理。是否允许模块的某些特性,如频段模式及 SIM 卡电压等。 29.AT+WCFM 商业特性管理。是否允许 Wavecom 特殊特性。 30.AT+WMIR 允许从当前存储的参数值创建定制的存储镜像 31.AT+WCDP 改变旋律的缺省播放器。 十 三 .SIM 卡 工 具 箱 命 令 1.AT+STSF 配置工具箱实用程序。 2.AT+STIN 工具箱指示。 3.AT+STGI 获得从 SIM 卡发来的预期命令的信息。 4.AT+STCR 主动提供的结果:工具箱控制反应。 5.AT+STGR 给出响应。允许程序或用户从主菜单上选择项目,或响应某些命令。
先要把短信猫通过串口连到服务器上。
1 private SerialPort waveCommSerialPort; 2 3 public void Initialize() 4 { 5 try 6 { 7 string portName = ConfigurationManager.AppSettings["WAVECOMM"];//COM3 8 if (!string.IsNullOrEmpty(portName)) 9 { 10 if (waveCommSerialPort != null) 11 { 12 waveCommSerialPort.Close(); 13 } 14 waveCommSerialPort = new System.IO.Ports.SerialPort(); 15 waveCommSerialPort.PortName = portName; 16 waveCommSerialPort.BaudRate = 9600; 17 waveCommSerialPort.Open(); 18 waveCommSerialPort.Close(); 19 bInitializeSuccessful = true; 20 } 21 } 22 catch 23 { 24 if (waveCommSerialPort != null) waveCommSerialPort.Close(); 25 } 26 }
准备好从Serial Port 读写信息
1 private string RESULT_STRING = ""; 2 private string SUCCESS_KEYWORD = "OK"; 3 private ManualResetEvent COMMAND_SIGNAL = new ManualResetEvent(false); 4 5 public bool SendCommand(string strCommand, string strSuccessKeyword) 6 { 7 string strRslt = ""; 8 return SendCommand(strCommand, strSuccessKeyword, ref strRslt); 9 } 10 11 public bool SendCommand(string strCommand, string strSuccessKeyword, ref string result) 12 { 13 if (!bInitializeSuccessful) return false; 14 15 try 16 { 17 if (!waveCommSerialPort.IsOpen) waveCommSerialPort.Open(); 18 19 RESULT_STRING = ""; 20 SUCCESS_KEYWORD = strSuccessKeyword; 21 22 COMMAND_SIGNAL.Reset(); 23 waveCommSerialPort.DiscardNull = true; 24 waveCommSerialPort.DiscardInBuffer(); 25 waveCommSerialPort.DiscardOutBuffer(); 26 waveCommSerialPort.Write(strCommand); 27 waveCommSerialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(SerialPort_DataReceived); 28 waveCommSerialPort.ErrorReceived += new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived); 29 bool isSuccess = COMMAND_SIGNAL.WaitOne(10000); 30 result = RESULT_STRING; 31 return isSuccess; 32 } 33 catch 34 { 35 } 36 finally 37 { 38 RESULT_STRING = ""; 39 SUCCESS_KEYWORD = "OK"; 40 waveCommSerialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(SerialPort_DataReceived); 41 waveCommSerialPort.ErrorReceived -= new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived); 42 } 43 return false; 44 } 45 46 void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e) 47 { 48 throw new NotImplementedException(); 49 } 50 51 void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) 52 { 53 int bytestoread = this.waveCommSerialPort.BytesToRead; 54 if (bytestoread > 0) 55 { 56 RESULT_STRING += this.waveCommSerialPort.ReadExisting(); 57 if (!string.IsNullOrEmpty(SUCCESS_KEYWORD) && RESULT_STRING.Contains(SUCCESS_KEYWORD)) 58 { 59 COMMAND_SIGNAL.Set(); 60 } 61 } 62 else 63 { 64 COMMAND_SIGNAL.Set(); 65 } 66 } 67 68 private bool WaitSucceedKeyWord(string strSucceedKeyWord, ref string strRtn) 69 { 70 strRtn = ""; 71 int i = 0; 72 73 while (!strRtn.Contains(strSucceedKeyWord)) 74 { 75 if (strRtn.Contains("ERROR")) return false; 76 System.Threading.Thread.Sleep(10); 77 var newString = this.waveCommSerialPort.ReadExisting(); 78 if (string.IsNullOrEmpty(newString)) 79 { 80 if (i++ > 500) return false; 81 } 82 else 83 i = 0; 84 strRtn += newString; 85 } 86 System.Threading.Thread.Sleep(100); 87 strRtn += this.waveCommSerialPort.ReadExisting(); 88 return true; 89 }
初始化短信模块
1 this.SendCommand("AT+CNMI=2,1,0,1\r\n", "OK");// config the way of receiving SMS 2 this.SendCommand("AT+CMEE=1\r\n", "OK");// config error report
发送短信,文本方式
1 public bool SendTEXT(string mobile, string msgContent) 2 { 3 try 4 { 5 if (!waveCommSerialPort.IsOpen) waveCommSerialPort.Open(); 6 if (!SendCommand("AT\r\n", "OK")) 7 { 8 return false; 9 } 10 11 if (!SendCommand("AT+CMGF=1\r\n", "OK")) 12 { 13 return false; 14 } 15 16 var outstr = string.Format("AT+CMGS=\"{0}\"\r", mobile, "OK"); 17 if (!SendCommand(outstr, ">")) 18 { 19 return false; 20 } 21 22 outstr = msgContent + "\x001a"; 23 if (!SendCommand(outstr.Trim(), "OK")) 24 { 25 return false; 26 } 27 return true; 28 } 29 catch (Exception ex) 30 { 31 Trace.WriteLine(ex.Message); 32 return false; 33 } 34 finally 35 { 36 waveCommSerialPort.Close(); 37 } 38 }
发送短信,PDU方式
1 public bool SendPDU(string mobile, string msgContent) 2 { 3 try 4 { 5 var pdu = GetPDU(mobile, msgContent); 6 var len = (pdu.Length / 2) - 1; 7 if (!waveCommSerialPort.IsOpen) waveCommSerialPort.Open(); 8 if (!SendCommand("AT\r\n", "OK")) 9 { 10 return false; 11 } 12 13 if (!SendCommand("AT+CMGF=0\r\n", "OK")) 14 { 15 return false; 16 } 17 18 var outstr = string.Format("AT+CMGS={0}\r", len, "OK"); 19 if (!SendCommand(outstr, ">")) 20 { 21 return false; 22 } 23 24 outstr = pdu.Trim() + "\x001a"; 25 if (!SendCommand(outstr.Trim(), "OK")) 26 { 27 return false; 28 } 29 return true; 30 } 31 catch (Exception ex) 32 { 33 Trace.WriteLine(ex.Message); 34 return false; 35 } 36 finally 37 { 38 waveCommSerialPort.Close(); 39 } 40 }
PDU方式需要将消息格式转一下
1 /// <summary> 2 /// 将手机号码的奇偶数为替换,缺少末尾偶数位的话用F来代替 3 /// </summary> 4 /// <param name="strMobile">手机号码(前面加国际编号:中国86美国01)</param> 5 /// <returns></returns> 6 private static string ConverMobile(string strMobile) 7 { 8 if (strMobile.Length == 11) 9 { 10 strMobile = "86" + strMobile; 11 } 12 string strRtn = ""; 13 int length = strMobile.Length; 14 for (int i = 0; i < length; i += 2) 15 { 16 string str2; 17 string str1 = strMobile.Substring(i, 1); 18 if ((i + 1) == length) 19 { 20 str2 = "F"; 21 } 22 else 23 { 24 str2 = strMobile.Substring(i + 1, 1); 25 } 26 strRtn = strRtn + str2 + str1; 27 } 28 return strRtn; 29 } 30 31 /// <summary> 32 /// 短信内容转PDU 33 /// </summary> 34 /// <param name="strMsg">短信内容</param> 35 /// <returns></returns> 36 private static string ConverUniCode(string strMsg) 37 { 38 var encodingUTF = System.Text.Encoding.BigEndianUnicode; 39 string s = null; 40 byte[] encodedBytes = encodingUTF.GetBytes(strMsg); 41 for (int i = 0; i < encodedBytes.Length; i++) 42 { 43 s += BitConverter.ToString(encodedBytes, i, 1); 44 } 45 return s; 46 } 47 48 /// <summary> 49 /// 将短信内容和手机号码转换成pdu格式 50 /// </summary> 51 /// <param name="mobile">手机号码(前面加国际编号:中国86美国01)</param> 52 /// <param name="msgContent">短信内容</param> 53 /// <returns></returns> 54 private static string GetPDU(string mobile, string msgContent) 55 { 56 string str = "0011000DA1"; 57 string strMobilePDU = ConverMobile(mobile); 58 string strMsgContentPDU = ConverUniCode(msgContent); 59 int num = strMsgContentPDU.Length / 2; 60 string str5 = num.ToString("X"); 61 if (num < 0x10) 62 { 63 str5 = "0" + str5; 64 } 65 return (str + strMobilePDU + "0008A7" + str5 + strMsgContentPDU); 66 }
读短信
1 public SMSLog ReadTextMsg(int index) 2 { 3 SMSLog log = null; 4 if (index < 0 || index > 50) return log; 5 6 string result = string.Empty; 7 if (SendCommand("AT+CMGF=0\r\n", "OK", ref result)) 8 { 9 if (SendCommand("AT+CMGR=" + index.ToString() + "\r\n", "OK", ref result)) 10 { 11 log = new SMSLog() 12 { 13 Id = Guid.NewGuid(), 14 SMSType = SMSType.Receive 15 }; 16 17 string[] strMsg = result.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); 18 if (strMsg.Length >= 3) 19 { 20 if (strMsg[1].Contains("+CMGR:")) 21 { 22 string code = ""; 23 string sca = ""; 24 PDUDecoding.DecodingMsg(strMsg[2], ref log.PhoneFrom, ref log.SMSContent, ref log.ReceiveTime, ref code, ref sca); 25 } 26 } 27 } 28 } 29 30 if (string.IsNullOrEmpty(log.SMSContent) && log.PhoneFrom.Length > 50) 31 { 32 log.SMSContent = log.PhoneFrom; 33 log.PhoneFrom = ""; 34 } 35 return log; 36 }
PDU 解码
public class PDUDecoding { static public bool DecodingMsg(string s, ref string phone, ref string text, ref DateTime sendTime, ref string code, ref string SCA) { try { //短信中心号码解码 int iLength = int.Parse(s.Substring(0, 2), System.Globalization.NumberStyles.AllowHexSpecifier); if (iLength > 0) { if (s.Substring(2, 2) == "91") { SCA += "+"; iLength--; } for (int j = 0; j < iLength * 2; j += 2) { SCA += s.Substring(5 + j, 1); SCA += s.Substring(4 + j, 1); } if (SCA.EndsWith("F")) SCA = SCA.Remove(SCA.Length - 1, 1); } s = s.Remove(0, iLength * 2 + 6); //发送方手机号码解码 iLength = int.Parse(s.Substring(0, 2), System.Globalization.NumberStyles.AllowHexSpecifier); if (s.Substring(2, 2) == "91") { phone = "+"; } if (iLength % 2 == 1) iLength++; for (int j = 0; j < iLength; j += 2) { phone += s.Substring(5 + j, 1); phone += s.Substring(4 + j, 1); } if (phone.EndsWith("F")) phone = phone.Remove(phone.Length - 1, 1); s = s.Remove(0, iLength + 6); //编码方式 if (s.Substring(0, 2) == "08") code = "uc"; else if (s.Substring(0, 2) == "00") code = "7"; else code = "8"; s = s.Remove(0, 2); //短信发送时间解码 sendTime = new DateTime(int.Parse("20" + s.Substring(1, 1) + s.Substring(0, 1)), int.Parse(s.Substring(3, 1) + s.Substring(2, 1)), int.Parse(s.Substring(5, 1) + s.Substring(4, 1)), int.Parse(s.Substring(7, 1) + s.Substring(6, 1)), int.Parse(s.Substring(9, 1) + s.Substring(8, 1)), int.Parse(s.Substring(11, 1) + s.Substring(10, 1))); s = s.Remove(0, 16); if (code == "uc") { text = DecodingUCS2(s); } else if (code == "7") { text = DecodingBit7(s); } else { text = DecodingBit8(s); } return true; } catch { return false; } } //中文短信息UCS2解码 static public string DecodingUCS2(string s) { byte[] buf = new byte[s.Length]; for (int i = 0; i < s.Length; i += 4) { buf[i / 2] = byte.Parse(s.Substring(2 + i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); buf[i / 2 + 1] = byte.Parse(s.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); } return Encoding.Unicode.GetString(buf); } // 使用8-bit进行解码 static public string DecodingBit8(string s) { byte[] buf = new byte[s.Length / 2]; StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.Length; i += 2) { buf[i / 2] = byte.Parse(s.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); } return Encoding.ASCII.GetString(buf); } // 使用7-bit进行解码 static public string DecodingBit7(string s) { int iByte = 0; int iLeft = 0; var sb = new System.Text.StringBuilder(); for (int i = 0; i < s.Length; i += 2) { byte bSrc = byte.Parse(s.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); sb.Append((((bSrc << iByte) | iLeft) & 0x7f).ToString("X2")); iLeft = bSrc >> (7 - iByte); iByte++; if (iByte == 7) { sb.Append(iLeft.ToString("X2")); iByte = 0; iLeft = 0; } } string sReturn = sb.ToString(); byte[] buf = new byte[sReturn.Length / 2]; for (int i = 0; i < sReturn.Length; i += 2) { buf[i / 2] = byte.Parse(sReturn.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier); } return System.Text.Encoding.ASCII.GetString(buf); } }