.Net/C# 實現 中國移動 CMPP v3.0 ISMG SP 收發簡訊的 SP 客戶端 (第2版)(CMPP SP Client)

.Net/C# 實現 中國移動 CMPP v3.0 ISMG SP 收發簡訊的 SP 客戶端 (第2版)(CMPP SP Client)2005-03-20 23:362216人閱讀評論(2)收藏舉報中國移動bufferterminalintegerstringbyte

/*.Net/C# 實現 中國移動 CMPP v3.0 ISMG <-> SP 收發簡訊的 SP 客戶端(第2版)(CMPP SP Client)

增加了 CMPP Client 類

本程序嚴格按《中國移動通信企業標準》之《中國移動通信互聯網簡訊網關介面協議(China Mobile Point to Point)》(版本號: 3.0.0)即: CMPP v3.0.0http://www.spzone.net/protocol/CMPPV3.0.rar文檔,實現了下面消息的定義及其相關協議級交互:

8.4業務提供商 (SP) 與互聯網簡訊網關 (ISMG) 間的消息定義88.4.1SP 請求連接到 ISMG(CMPP_CONNECT) 操作88.4.1.1CMPP_CONNECT 消息定義 (SP -> ISMG)88.4.1.2CMPP_CONNECT_RESP消息定義 (ISMG -> SP)98.4.2SP 或 ISMG 請求拆除連接 (CMPP_TERMINATE)操作98.4.2.1CMPP_TERMINATE 消息定義 (SP -> ISMG 或 ISMG -> SP)98.4.2.2CMPP_TERMINATE_RESP 消息定義 (SP -> ISMG 或 ISMG -> SP)108.4.3SP 向 ISMG提交簡訊 (CMPP_SUBMIT) 操作108.4.3.1CMPP_SUBMIT 消息定義 (SP -> ISMG)108.4.3.2CMPP_SUBMIT_RESP 消息定義 (ISMG -> SP)118.4.5ISMG 向 SP 送交簡訊 (CMPP_DELIVER) 操作138.4.5.1CMPP_DELIVER 消息定義 (ISMG -> SP)138.4.5.2CMPP_DELIVER_RESP 消息定義 (SP -> ISMG)168.4.7鏈路檢測 (CMPP_ACTIVE_TEST) 操作178.4.7.1CMPP_ACTIVE_TEST定義 (SP -> ISMG 或 ISMG <- SP)178.4.7.2CMPP_ACTIVE_TEST_RESP定義 (SP -> ISMG 或 ISMG <- SP)17

可採用《中國移動通信 CMPP v3.0 短消息網關模擬器 v1.10》進行測試:下載於: 《北京風起水流軟體工作室》http://www.zealware.com/download/cmpp3pro.rar

本程序以熟悉理解 CMPP 3.0 協議為主要目的,只將 "消息定義" 對象化,其相關協議級交互並未作更深層次的 OO!也暫無任何錯誤處理程序!消息定義的所有欄位名稱及其數據類型均與上述之 CMPP v3.0.0 文檔完全一致!

其間參閱過 shanhe@CSDN or yexiong@cnBlogs 大作(在此鳴謝):http://blog.csdn.net/shanhe/archive/2004/07/19/45383.aspxhttp://cnblogs.com/yexiong/articles/115330.aspx但其中有些消息定義位元組錯位,因此不能正常交互?!且對象化層次較高,不利於理解協議本身!遂自己動手,豐衣足食,實現部分主要協議(SP 收發簡訊):

playyuer㊣Microshaoft.com Invent.*/

namespace Microshaoft{using System;using System.Net.Sockets;

public class Util{private static object _SyncLockObject = new object();

public static string Get_MMDDHHMMSS_String(DateTime dt){string s = dt.Month.ToString().PadLeft(2, "0");s += dt.Day.ToString().PadLeft(2, "0");s += dt.Hour.ToString().PadLeft(2, "0");s += dt.Minute.ToString().PadLeft(2, "0");s += dt.Second.ToString().PadLeft(2, "0");return s;}

public static string Get_YYYYMMDD_String(DateTime dt){string s = dt.Year.ToString().PadLeft(4, "0");s += dt.Month.ToString().PadLeft(2, "0");s += dt.Day.ToString().PadLeft(2, "0");return s;}

internal static void WriteToStream(byte[] bytes, NetworkStream Stream){if (Stream.CanWrite){lock (_SyncLockObject){Stream.Write(bytes, 0, bytes.Length);}}}

internal static byte[] ReadFromStream(int Length, NetworkStream Stream){byte[] bytes = null;if (Stream.CanRead){if (Stream.DataAvailable){bytes = new byte[Length];int r = 0;int l = 0;lock (_SyncLockObject){while (l < Length){r = Stream.Read(bytes, l, Length - l);l += r;}}}}return bytes;}}}

//CMPP 消息定義namespace Microshaoft.CMPP.Messages{using System;using System.Text;using System.Security.Cryptography;

public enum CMPP_Command_Id : uint{CMPP_CONNECT = 0x00000001 //請求連接,CMPP_CONNECT_RESP = 0x80000001 //請求連接應答,CMPP_TERMINATE = 0x00000002 //終止連接,CMPP_TERMINATE_RESP = 0x80000002 //終止連接應答,CMPP_SUBMIT = 0x00000004 //提交簡訊,CMPP_SUBMIT_RESP = 0x80000004 //提交簡訊應答,CMPP_DELIVER = 0x00000005 //簡訊下發,CMPP_DELIVER_RESP = 0x80000005 //下發簡訊應答,CMPP_QUERY = 0x00000006 //發送簡訊狀態查詢,CMPP_QUERY_RESP = 0x80000006 //發送簡訊狀態查詢應答,CMPP_CANCEL = 0x00000007 //刪除簡訊,CMPP_CANCEL_RESP = 0x80000007 //刪除簡訊應答,CMPP_ACTIVE_TEST = 0x00000008 //激活測試,CMPP_ACTIVE_TEST_RESP = 0x80000008 //激活測試應答,CMPP_FWD = 0x00000009 //消息前轉,CMPP_FWD_RESP = 0x80000009 //消息前轉應答,CMPP_MT_ROUTE = 0x00000010 //MT路由請求,CMPP_MT_ROUTE_RESP = 0x80000010 //MT路由請求應答,CMPP_MO_ROUTE = 0x00000011 //MO路由請求,CMPP_MO_ROUTE_RESP = 0x80000011 //MO路由請求應答,CMPP_GET_MT_ROUTE = 0x00000012 //獲取MT路由請求,CMPP_GET_MT_ROUTE_RESP = 0x80000012 //獲取MT路由請求應答,CMPP_MT_ROUTE_UPDATE = 0x00000013 //MT路由更新,CMPP_MT_ROUTE_UPDATE_RESP = 0x80000013 //MT路由更新應答,CMPP_MO_ROUTE_UPDATE = 0x00000014 //MO路由更新,CMPP_MO_ROUTE_UPDATE_RESP = 0x80000014 //MO路由更新應答,CMPP_PUSH_MT_ROUTE_UPDATE = 0x00000015 //MT路由更新,CMPP_PUSH_MT_ROUTE_UPDATE_RESP = 0x80000015 //MT路由更新應答,CMPP_PUSH_MO_ROUTE_UPDATE = 0x00000016 //MO路由更新,CMPP_PUSH_MO_ROUTE_UPDATE_RESP = 0x80000016 //MO路由更新應答,CMPP_GET_MO_ROUTE = 0x00000017 //獲取MO路由請求,CMPP_GET_MO_ROUTE_RESP = 0x80000017 //獲取MO路由請求應答}

public class MessageHeader //消息頭{public const int Length = 4 + 4 + 4;//private byte[] _bytes = new byte[MessageHeader.Length];public CMPP_Command_Id Command_Id{get{return this._Command_Id;}}

public uint Sequence_Id{get{return this._Sequence_Id;}}

public uint Total_Length{get{return this._Total_Length;}}

private uint _Total_Length; //4Unsigned Integer消息總長度(含消息頭及消息體)private CMPP_Command_Id _Command_Id; //4Unsigned Integer命令或響應類型private uint _Sequence_Id; //4Unsigned Integer消息流水號,順序累加,步長為1,循環使用(一對請求和應答消息的流水號必須相同)

public MessageHeader(uint Total_Length, CMPP_Command_Id Command_Id, uint Sequence_Id) //發送前{this._Total_Length = Total_Length;this._Command_Id = Command_Id;this._Sequence_Id = Sequence_Id;}

public MessageHeader(byte[] bytes){byte[] buffer = new byte[4];Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Total_Length = BitConverter.ToUInt32(buffer, 0);

Buffer.BlockCopy(bytes, 4, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Command_Id = (CMPP_Command_Id) BitConverter.ToUInt32(buffer, 0);

Buffer.BlockCopy(bytes, 8, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Sequence_Id = BitConverter.ToUInt32(buffer, 0);}

public byte[] ToBytes(){byte[] bytes = new byte[MessageHeader.Length];

byte[] buffer = BitConverter.GetBytes(this._Total_Length);Array.Reverse(buffer);Buffer.BlockCopy(buffer, 0, bytes, 0, 4);

buffer = BitConverter.GetBytes((uint) this._Command_Id);Array.Reverse(buffer);Buffer.BlockCopy(buffer, 0, bytes, 4, 4);

buffer = BitConverter.GetBytes(this._Sequence_Id);Array.Reverse(buffer);Buffer.BlockCopy(buffer, 0, bytes, 8, 4);

return bytes;}}

public class CMPP_CONNECT //: CMPP_Request{public const int BodyLength = 6 + 16 + 1 + 4;

private string _Source_Addr; //6Octet String源地址,此處為SP_Id,即SP的企業代碼。private string _Password;private byte[] _AuthenticatorSource; //16Octet String用於鑒別源地址。其值通過單向MD5 hash計算得出,表示如下://AuthenticatorSource =//MD5(Source_Addr+9 位元組的0 +shared secret+timestamp)//Shared secret 由中國移動與源地址實體事先商定,timestamp格式為:MMDDHHMMSS,即月日時分秒,10位。private uint _Version; //1Unsigned Integer雙方協商的版本號(高位4bit表示主版本號,低位4bit表示次版本號),對於3.0的版本,高4bit為3,低4位為0private uint _Timestamp; //4Unsigned Integer時間戳的明文,由客戶端產生,格式為MMDDHHMMSS,即月日時分秒,10位數字的整型,右對齊 。

private MessageHeader _Header;

public MessageHeader Header{get{return this._Header;}}

public byte[] AuthenticatorSource{get{return this._AuthenticatorSource;}}

public CMPP_CONNECT(string Source_Addr, string Password, DateTime Timestamp, uint Version, uint Sequence_Id){this._Header = new MessageHeader(MessageHeader.Length + BodyLength, CMPP_Command_Id.CMPP_CONNECT, Sequence_Id);

this._Source_Addr = Source_Addr;this._Password = Password;

string s = Util.Get_MMDDHHMMSS_String(Timestamp);this._Timestamp = UInt32.Parse(s);

byte[] buffer = new byte[6 + 9 + this._Password.Length + 10];Encoding.ASCII.GetBytes(this._Source_Addr).CopyTo(buffer, 0);Encoding.ASCII.GetBytes(this._Password).CopyTo(buffer, 6 + 9);Encoding.ASCII.GetBytes(s).CopyTo(buffer, 6 + 9 + this._Password.Length);this._AuthenticatorSource = new MD5CryptoServiceProvider().ComputeHash(buffer, 0, buffer.Length);

this._Version = Version;}

public byte[] ToBytes(){byte[] bytes = new byte[MessageHeader.Length + BodyLength];int i = 0;

//header 12byte[] buffer = this._Header.ToBytes();Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

//Source_Addr 6i += MessageHeader.Length;buffer = Encoding.ASCII.GetBytes(this._Source_Addr);Buffer.BlockCopy(buffer, 0, bytes, i, 6);

//AuthenticatorSource 16i += 6;buffer = this._AuthenticatorSource;Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //16

//version 1i += 16;bytes[i++] = (byte) this._Version; //版本

//Timestampbuffer = BitConverter.GetBytes(this._Timestamp);Array.Reverse(buffer);buffer.CopyTo(bytes, i);return (bytes);}}

public class CMPP_CONNECT_RESP //: CMPP_Response{private MessageHeader _Header;public const int BodyLength = 4 + 16 + 1;

private uint _Status; //4Unsigned Integer狀態//0:正確//1:消息結構錯//2:非法源地址//3:認證錯//4:版本太高//5~:其他錯誤private byte[] _AuthenticatorISMG; //16Octet StringISMG認證碼,用於鑒別ISMG。//其值通過單向MD5 hash計算得出,表示如下://AuthenticatorISMG =MD5(Status+AuthenticatorSource+shared secret),Shared secret 由中國移動與源地址實體事先商定,AuthenticatorSource為源地址實體發送給ISMG的對應消息CMPP_Connect中的值。// 認證出錯時,此項為空。private uint _Version; //1Unsigned Integer伺服器支持的最高版本號,對於3.0的版本,高4bit為3,低4位為0

public byte[] AuthenticatorISMG{get{return this._AuthenticatorISMG;}}

public uint Status{get{return this._Status;}}

public uint Version{get{return this._Version;}}

public MessageHeader Header{get{return this._Header;}}

public CMPP_CONNECT_RESP(byte[] bytes){//header 12int i = 0;byte[] buffer = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);this._Header = new MessageHeader(buffer);

//status 4i += MessageHeader.Length;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Status = BitConverter.ToUInt32(buffer, 0);

//AuthenticatorISMG 16i += 4;this._AuthenticatorISMG = new byte[16];Buffer.BlockCopy(bytes, MessageHeader.Length + 4, this._AuthenticatorISMG, 0, this._AuthenticatorISMG.Length);

//versioni += 16;this._Version = bytes[i];}}

public class CMPP_SUBMIT //: CMPP_Request{private int _BodyLength;//without _Dest_terminal_Id Msg_Contentpublic const int FixedBodyLength = 8+ 1+ 1+ 1+ 1+ 10+ 1+ 32+ 1+ 1+ 1+ 1+ 6+ 2+ 6+ 17+ 17+ 21+ 1//+ 32*DestUsr_tl+ 1+ 1//+ Msg_length+ 20;

private ulong _Msg_Id; //8Unsigned Integer信息標識。private uint _Pk_total; //1Unsigned Integer相同Msg_Id的信息總條數,從1開始。private uint _Pk_number; //1Unsigned Integer相同Msg_Id的信息序號,從1開始。private uint _Registered_Delivery; //1Unsigned Integer是否要求返回狀態確認報告://0:不需要;//1:需要。private uint _Msg_level; //1Unsigned Integer信息級別。private string _Service_Id; //10Octet String業務標識,是數字、字母和符號的組合。private uint _Fee_UserType; //1Unsigned Integer計費用戶類型欄位://0:對目的終端MSISDN計費;//1:對源終端MSISDN計費;//2:對SP計費;//3:表示本欄位無效,對誰計費參見Fee_terminal_Id欄位。private string _Fee_terminal_Id; //32Octet String被計費用戶的號碼,當Fee_UserType為3時該值有效,當Fee_UserType為0、1、2時該值無意義。private uint _Fee_terminal_type; //1Unsigned Integer被計費用戶的號碼類型,0:真實號碼;1:偽碼。private uint _TP_pId; //1Unsigned IntegerGSM協議類型。詳細是解釋請參考GSM03.40中的9.2.3.9。private uint _TP_udhi; //1Unsigned IntegerGSM協議類型。詳細是解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。private uint _Msg_Fmt; //1Unsigned Integer信息格式://0:ASCII串;//3:簡訊寫卡操作;//4:二進位信息;//8:UCS2編碼;//15:含GB漢字。。。。。。private string _Msg_src; //6Octet String信息內容來源(SP_Id)。private string _FeeType; //2Octet String資費類別://01:對"計費用戶號碼"免費;//02:對"計費用戶號碼"按條計信息費;//03:對"計費用戶號碼"按包月收取信息費。private string _FeeCode; //6Octet String資費代碼(以分為單位)。private string _ValId_Time; //17Octet String存活有效期,格式遵循SMPP3.3協議。private string _At_Time; //17Octet String定時發送時間,格式遵循SMPP3.3協議。private string _Src_Id; //21Octet String源號碼。SP的服務代碼或前綴為服務代碼的長號碼, 網關將該號碼完整的填到SMPP協議Submit_SM消息相應的source_addr欄位,該號碼最終在用戶手機上顯示為短消息的主叫號碼。private uint _DestUsr_tl; //1Unsigned Integer接收信息的用戶數量(小於100個用戶)。private string[] _Dest_terminal_Id; //32*DestUsr_tlOctet String接收簡訊的MSISDN號碼。

private uint _Dest_terminal_type; //1Unsigned Integer接收簡訊的用戶的號碼類型,0:真實號碼;1:偽碼。private uint _Msg_Length; //1Unsigned Integer信息長度(Msg_Fmt值為0時:<160個位元組;其它<=140個位元組),取值大於或等於0。private string _Msg_Content; //Msg_lengthOctet String信息內容。private string _LinkID; //20Octet String點播業務使用的LinkID,非點播類業務的MT流程不使用該欄位。

private MessageHeader _Header;

private uint _Sequence_Id;

public CMPP_SUBMIT(uint Sequence_Id){this._Sequence_Id = Sequence_Id;}

public byte[] ToBytes(){//Msg_Length Msg_Contentbyte[] buf;switch (this._Msg_Fmt){case 8:buf = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content);break;case 15: //gb2312buf = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content);break;case 0: //asciicase 3: //簡訊寫卡操作case 4: //二進位信息default:buf = Encoding.ASCII.GetBytes(this._Msg_Content);break;}

this._Msg_Length = (uint) buf.Length;this._BodyLength = (int) (FixedBodyLength + 32 * this._Dest_terminal_Id.Length + this._Msg_Length);byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];

int i = 0;

byte[] buffer = new byte[MessageHeader.Length];//headerthis._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_SUBMIT, this._Sequence_Id);buffer = this._Header.ToBytes();Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);i += MessageHeader.Length;

//Msg_Id //8 [12,19]buffer = new byte[8];buffer = BitConverter.GetBytes(this._Msg_Id);Array.Reverse(buffer);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]

//_Pk_totali += 8;bytes[i++] = (byte) this._Pk_total; //[20,20]bytes[i++] = (byte) this._Pk_number; //[21,21]bytes[i++] = (byte) this._Registered_Delivery; //[22,22]bytes[i++] = (byte) this._Msg_level; //[23,23]

//Service_Idbuffer = Encoding.ASCII.GetBytes(this._Service_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //10 //[24,33]

//Fee_UserTypei += 10;bytes[i++] = (byte) this._Fee_UserType; //[34,34]

//Fee_terminal_Idbuffer = Encoding.ASCII.GetBytes(this._Fee_terminal_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //32 //[35,66]

//Fee_terminal_typei += 32;bytes[i++] = (byte) this._Fee_terminal_type; //[67,67]bytes[i++] = (byte) this._TP_pId; //[68,68]bytes[i++] = (byte) this._TP_udhi; //[69,69]bytes[i++] = (byte) this._Msg_Fmt; //[70,70]

//Msg_srcbuffer = Encoding.ASCII.GetBytes(this._Msg_src);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[71,76]

//FeeTypei += 6;buffer = Encoding.ASCII.GetBytes(this._FeeType);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //2 //[77,78]

//FeeCodei += 2;buffer = Encoding.ASCII.GetBytes(this._FeeCode);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //6 //[79,84]

//ValId_Timei += 6;//buffer = Encoding.ASCII.GetBytes(this._ValId_Time);//Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //17 //[85,101]

//At_Timei += 17;//buffer = Encoding.ASCII.GetBytes(this._At_Time);//Buffer.BlockCopy(buffer , 0, bytes, i, buffer.Length); //17 //[102,118]

//Src_Idi += 17;buffer = Encoding.ASCII.GetBytes(this._Src_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //21 //[119,139]

//DestUsr_tli += 21;this._DestUsr_tl = (uint) this._Dest_terminal_Id.Length;bytes[i++] = (byte) this._DestUsr_tl; //[140,140]

//Dest_terminal_Idforeach (string s in this._Dest_terminal_Id){buffer = Encoding.ASCII.GetBytes(s);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);i += 32;}

//Dest_terminal_typebytes[i++] = (byte) this._Dest_terminal_type;//Msg_Lengthbytes[i++] = (byte) this._Msg_Length;

//Msg_Content//buffer = Encoding.Buffer.BlockCopy(buf, 0, bytes, i, buf.Length);

//LinkIDi += (int) this._Msg_Length;buffer = Encoding.ASCII.GetBytes(this._LinkID);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length); //20return bytes;}

public ulong Msg_Id{get{return this._Msg_Id;}set{this._Msg_Id = value;}}

public uint Pk_total{get{return this._Pk_total;}set{this._Pk_total = value;}}

public uint Pk_number{get{return this._Pk_number;}set{this._Pk_number = value;}}

public uint Registered_Delivery{get{return this._Registered_Delivery;}set{this._Registered_Delivery = value;}}

public uint Msg_level{get{return this._Msg_level;}set{this._Msg_level = value;}}

public string Service_Id{get{return this._Service_Id;}set{this._Service_Id = value;}}

public uint Fee_UserType{get{return this._Fee_UserType;}set{this._Fee_UserType = value;}}

public string Fee_terminal_Id{get{return this._Fee_terminal_Id;}set{this._Fee_terminal_Id = value;}}

public uint Fee_terminal_type{get{return this._Fee_terminal_type;}set{this._Fee_terminal_type = value;}}

public uint TP_pId{get{return this._TP_pId;}set{this._TP_pId = value;}}

public uint TP_udhi{get{return this._TP_udhi;}set{this._TP_udhi = value;}}

public uint Msg_Fmt{get{return this._Msg_Fmt;}set{this._Msg_Fmt = value;}}

public string Msg_src{get{return this._Msg_src;}set{_Msg_src = value;}}

public string FeeType{get{return this._FeeType;}set{this._FeeType = value;}}

public string FeeCode{get{return this._FeeCode;}set{this._FeeCode = value;}}

public string ValId_Time{get{return this._ValId_Time;}set{this._ValId_Time = value;}}

public string At_Time{get{return this._At_Time;}set{this._At_Time = value;}}

public string Src_Id{get{return this._Src_Id;}set{this._Src_Id = value;}}

public uint DestUsr_tl{get{return this._DestUsr_tl;}set{this._DestUsr_tl = value;}}

public string[] Dest_terminal_Id{get{return this._Dest_terminal_Id;}set{this._Dest_terminal_Id = value;}}

public uint Dest_terminal_type{get{return this._Dest_terminal_type;}set{this._Dest_terminal_type = value;}}

public uint Msg_Length{get{return this._Msg_Length;}set{this._Msg_Length = value;}}

public string Msg_Content{get{return this._Msg_Content;}set{this._Msg_Content = value;}}

public string LinkId{get{return this._LinkID;}set{this._LinkID = value;}}

}

public class CMPP_SUBMIT_RESP //: CMPP_Response{private MessageHeader _Header;private uint _Msg_Id;private uint _Result;

public const int BodyLength = 8 + 4;

public uint Msg_Id{get{return this._Msg_Id;}}

public uint Result{get{return this._Result;}}

public MessageHeader Header{get{return this._Header;}}

public CMPP_SUBMIT_RESP(byte[] bytes){int i = 0;byte[] buffer = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);this._Header = new MessageHeader(buffer);

//Msg_Idi += MessageHeader.Length;buffer = new byte[8];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

//Resulti += 8;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Result = BitConverter.ToUInt32(buffer, 0);}}

public class CMPP_DELIVER //: CMPP_Request{public ulong Msg_Id{get{return _Msg_Id;}}

public string Dest_Id{get{return _Dest_Id;}}

public string Service_Id{get{return _Service_Id;}}

public uint TP_pid{get{return _TP_pid;}}

public uint TP_udhi{get{return _TP_udhi;}}

public uint Msg_Fmt{get{return _Msg_Fmt;}}

public string Src_terminal_Id{get{return _Src_terminal_Id;}}

public uint Src_terminal_type{get{return _Src_terminal_type;}}

public uint Registered_Delivery{get{return _Registered_Delivery;}}

public uint Msg_Length{get{return _Msg_Length;}}

public string Msg_Content{get{return _Msg_Content;}}

public string LinkId{get{return _LinkID;}}

private ulong _Msg_Id; //8Unsigned Integer信息標識。//生成演算法如下://採用64位(8位元組)的整數://(1)????????? 時間(格式為MMDDHHMMSS,即月日時分秒):bit64~bit39,其中//bit64~bit61:月份的二進位表示;//bit60~bit56:日的二進位表示;//bit55~bit51:小時的二進位表示;//bit50~bit45:分的二進位表示;//bit44~bit39:秒的二進位表示;//(2)????????? 簡訊網關代碼:bit38~bit17,把簡訊網關的代碼轉換為整數填寫到該欄位中;//(3)????????? 序列號:bit16~bit1,順序增加,步長為1,循環使用。//各部分如不能填滿,左補零,右對齊。private string _Dest_Id; //21Octet String目的號碼。//SP的服務代碼,一般4--6位,或者是前綴為服務代碼的長號碼;該號碼是手機用戶短消息的被叫號碼。private string _Service_Id; //10Octet String業務標識,是數字、字母和符號的組合。private uint _TP_pid; //1Unsigned IntegerGSM協議類型。詳細解釋請參考GSM03.40中的9.2.3.9。private uint _TP_udhi; //1Unsigned IntegerGSM協議類型。詳細解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。private uint _Msg_Fmt; //1Unsigned Integer信息格式://0:ASCII串;//3:簡訊寫卡操作;//4:二進位信息;//8:UCS2編碼;//15:含GB漢字。private string _Src_terminal_Id; //32Octet String源終端MSISDN號碼(狀態報告時填為CMPP_SUBMIT消息的目的終端號碼)。private uint _Src_terminal_type; //1Unsigned Integer源終端號碼類型,0:真實號碼;1:偽碼。private uint _Registered_Delivery; //1Unsigned Integer是否為狀態報告://0:非狀態報告;//1:狀態報告。private uint _Msg_Length; //1Unsigned Integer消息長度,取值大於或等於0。private string _Msg_Content; //Msg_lengthOctet String消息內容。private string _LinkID; //20Octet String點播業務使用的LinkID,非點播類業務的MT流程不使用該欄位。

private MessageHeader _Header;

public MessageHeader Header{get{return this._Header;}}

public const int FixedBodyLength = 8 //Msg_IdUnsigned Integer信息標識。//生成演算法如下://採用64位(8位元組)的整數://(1)????????? 時間(格式為MMDDHHMMSS,即月日時分秒):bit64~bit39,其中//bit64~bit61:月份的二進位表示;//bit60~bit56:日的二進位表示;//bit55~bit51:小時的二進位表示;//bit50~bit45:分的二進位表示;//bit44~bit39:秒的二進位表示;//(2)????????? 簡訊網關代碼:bit38~bit17,把簡訊網關的代碼轉換為整數填寫到該欄位中;//(3)????????? 序列號:bit16~bit1,順序增加,步長為1,循環使用。//各部分如不能填滿,左補零,右對齊。+ 21 //Dest_IdOctet String目的號碼。//SP的服務代碼,一般4--6位,或者是前綴為服務代碼的長號碼;該號碼是手機用戶短消息的被叫號碼。+ 10 //Service_IdOctet String業務標識,是數字、字母和符號的組合。+ 1 //TP_pidUnsigned IntegerGSM協議類型。詳細解釋請參考GSM03.40中的9.2.3.9。+ 1 //TP_udhiUnsigned IntegerGSM協議類型。詳細解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。+ 1 //Msg_FmtUnsigned Integer信息格式://0:ASCII串;//3:簡訊寫卡操作;//4:二進位信息;//8:UCS2編碼;//15:含GB漢字。+ 32 //Src_terminal_IdOctet String源終端MSISDN號碼(狀態報告時填為CMPP_SUBMIT消息的目的終端號碼)。+ 1 //Src_terminal_typeUnsigned Integer源終端號碼類型,0:真實號碼;1:偽碼。+ 1 //Registered_DeliveryUnsigned Integer是否為狀態報告://0:非狀態報告;//1:狀態報告。+ 1 //Msg_LengthUnsigned Integer消息長度,取值大於或等於0。//Msg_length//Msg_ContentOctet String消息內容。+ 20; //LinkIDOctet String點播業務使用的LinkID,非點播類業務的MT流程不使用該欄位。private int _BodyLength;

public int BodyLength{get{return this._BodyLength;}}

public CMPP_DELIVER(byte[] bytes){int i = 0;byte[] buffer = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, 0, buffer, 0, MessageHeader.Length);this._Header = new MessageHeader(buffer);

//Msg_Id 8i += MessageHeader.Length;buffer = new byte[8];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Msg_Id = BitConverter.ToUInt64(buffer, 0);

//Dest_Id 21i += 8;buffer = new byte[21];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Dest_Id = Encoding.ASCII.GetString(buffer).Trim();

//Service_Id 20i += 21;buffer = new byte[10];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Service_Id = Encoding.ASCII.GetString(buffer).Trim();

//TP_pid 1i += 10;this._TP_pid = (uint) bytes[i++];this._TP_udhi = (uint) bytes[i++];this._Msg_Fmt = (uint) bytes[i++];

//Src_terminal_Id 32buffer = new byte[32];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Src_terminal_Id = Encoding.ASCII.GetString(buffer).Trim();

//Src_terminal_type 1i += 32;this._Src_terminal_type = (uint) bytes[i++];this._Registered_Delivery = (uint) bytes[i++];this._Msg_Length = (uint) bytes[i++];

//Msg_Contentbuffer = new byte[this._Msg_Length];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);switch (this._Msg_Fmt){case 8:this._Msg_Content = Encoding.BigEndianUnicode.GetString(buffer).Trim();break;case 15: //gb2312this._Msg_Content = Encoding.GetEncoding("gb2312").GetString(buffer).Trim();break;case 0: //asciicase 3: //簡訊寫卡操作case 4: //二進位信息default:this._Msg_Content = Encoding.ASCII.GetString(buffer).ToString();break;}

//Linkid 20i += (int) this._Msg_Length;buffer = new byte[20];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._LinkID = Encoding.ASCII.GetString(buffer).Trim();

}

public byte[] ToBytes(){ //Msg_Length Msg_Contentbyte[] buf;switch (this._Msg_Fmt){case 8:buf = Encoding.BigEndianUnicode.GetBytes(this._Msg_Content);break;case 15: //gb2312buf = Encoding.GetEncoding("gb2312").GetBytes(this._Msg_Content);break;case 0: //asciicase 3: //簡訊寫卡操作case 4: //二進位信息default:buf = Encoding.ASCII.GetBytes(this._Msg_Content);break;}

this._Msg_Length = (uint) buf.Length;this._BodyLength = FixedBodyLength + (int) this._Msg_Length;

byte[] bytes = new byte[MessageHeader.Length + this._BodyLength];

int i = 0;

byte[] buffer = null;//header 12this._Header = new MessageHeader((uint) (MessageHeader.Length + this._BodyLength), CMPP_Command_Id.CMPP_DELIVER, 0);

//Msg_Id 8i += MessageHeader.Length;buffer = new Byte[8];buffer = BitConverter.GetBytes(this._Msg_Id);Array.Reverse(buffer);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

//Dest_Id 21i += 8;buffer = new byte[21];buffer = Encoding.ASCII.GetBytes(this._Dest_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

//Service_Id 10i += 21;buffer = new byte[10];buffer = Encoding.ASCII.GetBytes(this._Service_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

//TP_pid 1i += 10;bytes[i++] = (byte) this._TP_pid;bytes[i++] = (byte) this._TP_udhi;bytes[i++] = (byte) this._Msg_Fmt;

//Src_terminal_Id 32buffer = new byte[32];buffer = Encoding.ASCII.GetBytes(this._Src_terminal_Id);Buffer.BlockCopy(buffer, 0, bytes, i, buffer.Length);

//Src_terminal_type 1i += 32;bytes[i++] = (byte) this._Src_terminal_type;bytes[i++] = (byte) this._Registered_Delivery;bytes[i++] = (byte) this._Msg_Length;

//Msg_ContentBuffer.BlockCopy(buf, 0, bytes, i, buf.Length);

//LinkIDi += (int) this._Msg_Length;

return bytes;}}

public class CMPP_DELIVER_RESP //: CMPP_Response{private MessageHeader _Header;private ulong _Msg_Id;private uint _Result;public const int Bodylength = 8 + 4;

public CMPP_DELIVER_RESP(ulong Msg_Id, uint Result){this._Msg_Id = Msg_Id;this._Result = Result;}

public byte[] ToBytes(){int i = 0;byte[] bytes = new byte[MessageHeader.Length + Bodylength];

byte[] buffer = new byte[MessageHeader.Length];//headerthis._Header = new MessageHeader(MessageHeader.Length + Bodylength, CMPP_Command_Id.CMPP_DELIVER_RESP, 0);buffer = this._Header.ToBytes();Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);i += MessageHeader.Length;

//msg_id 8buffer = BitConverter.GetBytes(this._Msg_Id);Array.Reverse(buffer);buffer.CopyTo(bytes, i);

//result 4i += 8;buffer = BitConverter.GetBytes(this._Result);Array.Reverse(buffer);buffer.CopyTo(bytes, i);return bytes;

}}

public class CMPP_Msg_Content //狀態報告{public const int BodyLength = 8 + 7 + 10 + 10 + 32 + 4;private uint _Msg_Id; //8Unsigned Integer信息標識。SP提交簡訊(CMPP_SUBMIT)操作時,與SP相連的ISMG產生的Msg_Id。private string _Stat; //7Octet String發送簡訊的應答結果,含義詳見表一。SP根據該欄位確定CMPP_SUBMIT消息的處理狀態。private string _Submit_time; //10Octet StringYYMMDDHHMM(YY為年的後兩位00-99,MM:01-12,DD:01-31,HH:00-23,MM:00-59)。private string _Done_time; //10Octet StringYYMMDDHHMM。public CMPP_Msg_Content(byte[] bytes){if (bytes.Length == BodyLength){int i = 0;//_Msg_Id 8byte[] buffer = new byte[8];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._Msg_Id = BitConverter.ToUInt32(buffer, 0);

//_Stat 7i += 8;buffer = new byte[7];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Stat = Encoding.ASCII.GetString(buffer);

//_Submit_time 10i += 7;buffer = new byte[10];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Submit_time = Encoding.ASCII.GetString(buffer);

//_Done_time 10i += 10;buffer = new byte[10];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Submit_time = Encoding.ASCII.GetString(buffer);

//Dest_terminal_Id 32i += 10;buffer = new byte[32];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Dest_terminal_Id = Encoding.ASCII.GetString(buffer);

//SMSC_sequence 4i += 32;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._SMSC_sequence = BitConverter.ToUInt32(buffer, 0);}}

public uint Msg_Id{get{return this._Msg_Id;}set{this._Msg_Id = value;}}

public string Stat{get{return this._Stat;}set{this._Stat = value;}}

public string Submit_time{get{return this._Submit_time;}set{this._Submit_time = value;}}

public string Done_time{get{return this._Done_time;}set{this._Done_time = value;}}

public string Dest_terminal_Id{get{return this._Dest_terminal_Id;}set{this._Dest_terminal_Id = value;}}

public uint SMSC_sequence{get{return this._SMSC_sequence;}set{this._SMSC_sequence = value;}}

private string _Dest_terminal_Id; //32Octet String目的終端MSISDN號碼(SP發送CMPP_SUBMIT消息的目標終端)。private uint _SMSC_sequence; //4Unsigned Integer取自SMSC發送狀態報告的消息體中的消息標識。}

public class CMPP_QUERY //: CMPP_Request{private MessageHeader _Header;

private string _Time; //8Octet String時間YYYYMMDD(精確至日)。private uint _Query_Type; //1Unsigned Integer查詢類別://0:總數查詢;//1:按業務類型查詢。private string _Query_Code; //10Octet String查詢碼。//當Query_Type為0時,此項無效;當Query_Type為1時,此項填寫業務類型Service_Id.。private string _Reserve; //8Octet String保留。

public MessageHeader Header{get{return this._Header;}}

public string Time{get{return this._Time;}}

public uint Query_Type{get{return this._Query_Type;}}

public string Query_Code{get{return this._Query_Code;}}

public string Reserve{get{return this._Reserve;}}

public const int BodyLength = 8 + 1 + 10 + 8;

public CMPP_QUERY(System.DateTime Time, uint Query_Type, string Query_Code, string Reserve, uint Sequence_Id){this._Time = Util.Get_YYYYMMDD_String(Time);this._Query_Type = Query_Type;this._Query_Code = Query_Code;this._Reserve = Reserve;this._Header = new MessageHeader((uint) (MessageHeader.Length + BodyLength), CMPP_Command_Id.CMPP_QUERY, Sequence_Id);}

public byte[] ToBytes(){int i = 0;byte[] bytes = new byte[MessageHeader.Length + BodyLength];//header

byte[] buffer = new byte[MessageHeader.Length];buffer = this._Header.ToBytes();buffer.CopyTo(bytes, 0);

//Time 8i += MessageHeader.Length;buffer = new byte[10];buffer = Encoding.ASCII.GetBytes(this._Time);buffer.CopyTo(bytes, i);

//Query_Type 1i += 8;bytes[i++] = (byte) this._Query_Type;

//Query_Code 10buffer = new byte[10];buffer = Encoding.ASCII.GetBytes(this._Query_Code);buffer.CopyTo(bytes, i);

//Reserve 8i += 10;buffer = new byte[8];buffer = Encoding.ASCII.GetBytes(this._Reserve);buffer.CopyTo(bytes, i);

return bytes;}}

public class CMPP_QUERY_RESP{public MessageHeader Header{get{return this._Header;}}

public string Time{get{return this._Time;}}

public uint Query_Type{get{return this._Query_Type;}}

public string Query_Code{get{return this._Query_Code;}}

public uint Mt_TlMsg{get{return this._MT_TLMsg;}}

public uint Mt_Tlusr{get{return this._MT_Tlusr;}}

public uint Mt_Scs{get{return this._MT_Scs;}}

public uint MT_WT{get{return this._MT_WT;}}

public uint MT_FL{get{return this._MT_FL;}}

public uint MO_Scs{get{return this._MO_Scs;}}

public uint MO_WT{get{return this._MO_WT;}}

public uint MO_FL{get{return this._MO_FL;}}

private MessageHeader _Header;private string _Time; //8Octet String時間(精確至日)。private uint _Query_Type; //1Unsigned Integer查詢類別://0:總數查詢;//1:按業務類型查詢。private string _Query_Code; //10Octet String查詢碼。private uint _MT_TLMsg; //4Unsigned Integer從SP接收信息總數。private uint _MT_Tlusr; //4Unsigned Integer從SP接收用戶總數。private uint _MT_Scs; //4Unsigned Integer成功轉發數量。private uint _MT_WT; //4Unsigned Integer待轉發數量。private uint _MT_FL; //4Unsigned Integer轉發失敗數量。private uint _MO_Scs; //4Unsigned Integer向SP成功送達數量。private uint _MO_WT; //4Unsigned Integer向SP待送達數量。private uint _MO_FL; //4Unsigned Integer向SP送達失敗數量。

public const int BodyLength = 8 //Octet String時間(精確至日)。+ 1 //Unsigned Integer查詢類別://0:總數查詢;//1:按業務類型查詢。+ 10 //Octet String查詢碼。+ 4 //Unsigned Integer從SP接收信息總數。+ 4 //Unsigned Integer從SP接收用戶總數。+ 4 //Unsigned Integer成功轉發數量。+ 4 //Unsigned Integer待轉發數量。+ 4 //Unsigned Integer轉發失敗數量。+ 4 //Unsigned Integer向SP成功送達數量。+ 4 //Unsigned Integer向SP待送達數量。+ 4; //Unsigned Integer向SP送達失敗數量。

public CMPP_QUERY_RESP(byte[] bytes){int i = 0;//header 12byte[] buffer = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, 0, buffer, 0, buffer.Length);this._Header = new MessageHeader(buffer);

//Time 8i += MessageHeader.Length;buffer = new byte[8];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Time = Encoding.ASCII.GetString(buffer);

//Query_Type 1i += 8;this._Query_Type = (uint) bytes[i++];

//Query_Code 10buffer = new byte[10];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Query_Code = Encoding.ASCII.GetString(buffer);

//MT_TLMsg 4i += 10;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MT_TLMsg = BitConverter.ToUInt32(buffer, 0);

//MT_Tlusr 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MT_Tlusr = BitConverter.ToUInt32(buffer, 0);

//MT_Scs 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MT_Scs = BitConverter.ToUInt32(buffer, 0);

//MT_WT 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MT_WT = BitConverter.ToUInt32(buffer, 0);

//MT_FL 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MT_FL = BitConverter.ToUInt32(buffer, 0);

//MO_Scs 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MO_Scs = BitConverter.ToUInt32(buffer, 0);

//MO_WT 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MO_WT = BitConverter.ToUInt32(buffer, 0);

//MO_FL 4i += 4;buffer = new byte[4];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);Array.Reverse(buffer);this._MO_FL = BitConverter.ToUInt32(buffer, 0);}}

public class CMPP_ACTIVE_TEST{private MessageHeader _Header;

public MessageHeader Header{get{return this._Header;}}

public CMPP_ACTIVE_TEST(uint Sequence_Id){this._Header = new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, Sequence_Id);}

public byte[] ToBytes(){return this._Header.ToBytes();}}

public class CMPP_ACTIVE_TEST_RESP{private MessageHeader _Header;private byte _Reserved;

public byte Reserved{get{return this._Reserved;}}

public MessageHeader Header{get{return this._Header;}}

public CMPP_ACTIVE_TEST_RESP(byte[] bytes){int i = 0;//headerbyte[] buffer = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, i, buffer, 0, buffer.Length);this._Header = new MessageHeader(buffer);

//Reserved 1i += MessageHeader.Length;this._Reserved = bytes[i];}

public byte[] ToBytes(){return this._Header.ToBytes();}}

}

//CMPP Clientnamespace Microshaoft.CMPP{using System;using System.Net.Sockets;using System.Threading;using Microshaoft.CMPP.Messages;

public class ResponseEventArgs : System.EventArgs{private byte[] _ResponseHeaderData;private MessageHeader _ResponseHeader;public byte[] _ResponseBodyData;

public byte[] ResponseBodyData{get{return this._ResponseBodyData;}}

public MessageHeader ResponseHeader{get{return this._ResponseHeader;}}

public byte[] ResponseHeaderData{get{return this._ResponseHeaderData;}}

public ResponseEventArgs(byte[] bytes){this._ResponseHeaderData = new byte[MessageHeader.Length];Buffer.BlockCopy(bytes, 0, this._ResponseHeaderData, 0, MessageHeader.Length);this._ResponseHeader = new MessageHeader(this._ResponseHeaderData);this._ResponseBodyData = new byte[this._ResponseHeader.Total_Length - MessageHeader.Length];Buffer.BlockCopy(bytes, MessageHeader.Length, this._ResponseBodyData, 0, this._ResponseBodyData.Length);}

}

public class Client{private string _Host;private int _Port;private string _Source_Addr;private string _Password;

private TcpClient tc;

private bool _IsConnected;

public bool IsConnected{get{return this._IsConnected;}}

private NetworkStream _NetworkStream;

//private static object _SyncLockObject = new object();

public delegate void ResponseEventHandler(Client Sender, ResponseEventArgs e);

public event ResponseEventHandler ResponseReceive;

private Thread _ReadResponseThread;

public void Terminate(uint SequenceId){Util.WriteToStream(new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_TERMINATE, SequenceId).ToBytes(), this._NetworkStream);this.StartRun();}

public void ActiveTest(uint SequenceId){Util.WriteToStream(new MessageHeader(MessageHeader.Length, CMPP_Command_Id.CMPP_ACTIVE_TEST, SequenceId).ToBytes(), this._NetworkStream);this.StartRun();}

public bool Connect(string Host, int Port, string UserID, string Password, uint SequenceId){this._Host = Host;this._Port = Port;this._Source_Addr = UserID;this._Password = Password;

DateTime ts = DateTime.Now;CMPP_CONNECT connect = new CMPP_CONNECT(this._Source_Addr, this._Password, ts, 1, SequenceId);

tc = new TcpClient();tc.Connect(this._Host, this._Port);this._NetworkStream = tc.GetStream();

Util.WriteToStream(connect.ToBytes(), this._NetworkStream);

this.Run(ref this._IsConnected);return this._IsConnected;

}

public void Query(DateTime Time, uint QueryType, string QueryCode, string Reserve, uint SequenceId){Util.WriteToStream(new CMPP_QUERY(Time, QueryType, QueryCode, Reserve, SequenceId).ToBytes(), this._NetworkStream);this.StartRun();}

public void Submit(ulong MsgId, string FeeTerminalId, string[] DestTerminalId, string MsgContent, uint SequenceId){CMPP_SUBMIT submit = new CMPP_SUBMIT(SequenceId);submit.Msg_Id = MsgId; //uint _Msg_Id; //8Unsigned Integer信息標識。submit.Pk_total = 1; //uint _Pk_total; //1Unsigned Integer相同Msg_Id的信息總條數,從1開始。submit.Pk_number = 0; //uint _Pk_number; //1Unsigned Integer相同Msg_Id的信息序號,從1開始。submit.Registered_Delivery = 1; //uint _Registered_Delivery; //1Unsigned Integer是否要求返回狀態確認報告:////0:不需要;////1:需要。submit.Msg_level = 1; //uint _Msg_level; //1Unsigned Integer信息級別。submit.Service_Id = "abcdefghij"; //string _Service_Id; //10Octet String業務標識,是數字、字母和符號的組合。submit.Fee_UserType = 3; //uint _Fee_UserType; //1Unsigned Integer計費用戶類型欄位:////0:對目的終端MSISDN計費;////1:對源終端MSISDN計費;////2:對SP計費;////3:表示本欄位無效,對誰計費參見Fee_terminal_Id欄位。submit.Fee_terminal_Id = FeeTerminalId; //string _Fee_terminal_Id; //32Octet String被計費用戶的號碼,當Fee_UserType為3時該值有效,當Fee_UserType為0、1、2時該值無意義。submit.Fee_terminal_type = 0; //uint _Fee_terminal_type; //1Unsigned Integer被計費用戶的號碼類型,0:真實號碼;1:偽碼。

submit.TP_pId = 0; //uint _TP_pId; //1Unsigned IntegerGSM協議類型。詳細是解釋請參考GSM03.40中的9.2.3.9。submit.TP_udhi = 0; //uint _TP_udhi; //1Unsigned IntegerGSM協議類型。詳細是解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊。submit.Msg_Fmt = 15; //uint _Msg_Fmt; //1Unsigned Integer信息格式:////0:ASCII串;////3:簡訊寫卡操作;////4:二進位信息;////8:UCS2編碼;////15:含GB漢字。。。。。。submit.Msg_src = this._Source_Addr; //string _Msg_src; //6Octet String信息內容來源(SP_Id)。submit.FeeType = "02"; //string _FeeType; //2Octet String資費類別:////01:對"計費用戶號碼"免費;////02:對"計費用戶號碼"按條計信息費;////03:對"計費用戶號碼"按包月收取信息費。submit.FeeCode = "100"; //string _FeeCode; //6Octet String資費代碼(以分為單位)。//Why not 17?submit.ValId_Time = Util.Get_MMDDHHMMSS_String(DateTime.Now.AddHours(2)) + "032+"; //string _ValId_Time; //17Octet String存活有效期,格式遵循SMPP3.3協議。submit.At_Time = Util.Get_MMDDHHMMSS_String(DateTime.Now) + "032+"; //string _At_Time; //17Octet String定時發送時間,格式遵循SMPP3.3協議。//spnumsubmit.Src_Id = ""; //string _Src_Id; //21Octet String源號碼。SP的服務代碼或前綴為服務代碼的長號碼, 網關將該號碼完整的填到SMPP協議Submit_SM消息相應的source_addr欄位,該號碼最終在用戶手機上顯示為短消息的主叫號碼。

submit.Dest_terminal_Id = DestTerminalId; //new string[] {"1391xxx1138", "1391xxx1137"}; //string[] _Dest_terminal_Id; //32*DestUsr_tlOctet String接收簡訊的MSISDN號碼。submit.DestUsr_tl = (uint) submit.Dest_terminal_Id.Length; //uint _DestUsr_tl; //1Unsigned Integer接收信息的用戶數量(小於100個用戶)。

submit.Dest_terminal_type = 0; //uint _Dest_terminal_type; //1Unsigned Integer接收簡訊的用戶的號碼類型,0:真實號碼;1:偽碼。submit.Msg_Fmt = 15; //uint _Msg_Length; //1Unsigned Integer信息長度(Msg_Fmt值為0時:<160個位元組;其它<=140個位元組),取值大於或等於0。submit.Msg_Content = MsgContent; //"大家好!這是一個簡訊群發測試!"; //string _Msg_Content; //Msg_lengthOctet String信息內容。submit.LinkId = ""; //string _LinkID; //20Octet String點播業務使用的LinkID,非點播類業務的MT流程不使用該欄位。Util.WriteToStream(submit.ToBytes(), this._NetworkStream);this.StartRun();}

bool _b = false;private bool _IsStarted = false;

public void StartRun(){if (!this._IsStarted){this._IsStarted = true;if (this._ReadResponseThread == null){this._ReadResponseThread = new Thread(new ThreadStart(this.Run));}if (this._ReadResponseThread.ThreadState == ThreadState.Unstarted){this._ReadResponseThread.Start();}}}

private void Run(){this.Run(ref this._b);}

private void Run(ref bool BreakFlag){while (!BreakFlag){if (this._NetworkStream.CanRead){if (this._NetworkStream.DataAvailable){byte[] buffer = new byte[MessageHeader.Length]; //Headerbuffer = Util.ReadFromStream(MessageHeader.Length, this._NetworkStream);MessageHeader header = new MessageHeader(buffer);byte[] bytes = new byte[header.Total_Length];Buffer.BlockCopy(buffer, 0, bytes, 0, buffer.Length);

int l = (int) header.Total_Length - MessageHeader.Length;if (l > 0){buffer = Util.ReadFromStream(l, this._NetworkStream);Buffer.BlockCopy(buffer, 0, bytes, MessageHeader.Length, buffer.Length);}if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP){CMPP_CONNECT_RESP connect_resp = new CMPP_CONNECT_RESP(bytes);this._IsConnected = connect_resp.Status == 0;}else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP){this._b = true;}if (ResponseReceive != null){ResponseReceive(this, new ResponseEventArgs(bytes));}}}}if (this._b){this._NetworkStream.Close();this._NetworkStream = null;}}}}

//測試程序namespace Test{using System;using System.Text;using Microshaoft.CMPP.Messages;using Microshaoft.CMPP;

class ConsoleApplication{static void Main(){ConsoleApplication a = new ConsoleApplication();Client c = new Client();c.ResponseReceive += new Microshaoft.CMPP.Client.ResponseEventHandler(a.c_ResponseReceive);Console.WriteLine("press "q" to exit this programe!");uint i = 0; //Sequence_Id headerulong l = 0; //Msg_Id bodyif (c.Connect("localhost", 7890, "901234", "1234", ++i)){c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, "卧鼠藏蟲 身披七彩祥雲 腳踏金甲聖衣", ++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);c.Query(DateTime.Parse("2005-1-1"), 1, "001", "", ++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);c.ActiveTest(++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, "欲窮千里目 粒粒皆辛苦", ++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}", i, l);//c.StartRun();}

string s;while ((s = Console.ReadLine()) != "q"){if (c.IsConnected){if (s.Length > 0){c.Submit(++l, "1391xxx1138", new string[] {"13911234567"}, s, ++i);Console.WriteLine("Request: Sequence_Id: {0},Msg_Id: {1}, Content: /"{2}/"", i, l, s);}else{Console.WriteLine("you can submit your SMS at here,or press "q" to exit this programe!");}}}if (c.IsConnected){c.Terminate(++i);}

Console.ReadLine();}

private void c_ResponseReceive(Client Sender, ResponseEventArgs e){MessageHeader header = e.ResponseHeader;this.PrintHeader(header);byte[] bytes = new byte[header.Total_Length];e.ResponseHeaderData.CopyTo(bytes, 0);e.ResponseBodyData.CopyTo(bytes, MessageHeader.Length);string s = "";if (header.Command_Id == CMPP_Command_Id.CMPP_ACTIVE_TEST_RESP){CMPP_ACTIVE_TEST_RESP response = new CMPP_ACTIVE_TEST_RESP(bytes);Console.WriteLine(response.Reserved);}else if (header.Command_Id == CMPP_Command_Id.CMPP_CONNECT_RESP){CMPP_CONNECT_RESP response = new CMPP_CONNECT_RESP(bytes);s = String.Format("CMPP_CONNECT_RESP Status: {0}", response.Status);}else if (header.Command_Id == CMPP_Command_Id.CMPP_DELIVER){CMPP_DELIVER response = new CMPP_DELIVER(bytes);//s = String.Format("CMPP_DELIVER : {0},{1}",response.Src_terminal_Id,response.Msg_Content);if (response.Registered_Delivery == 0) //普通簡訊{s = String.Format("收到普通簡訊: /n{0}/n{1}", response.Src_terminal_Id, response.Msg_Content);}else//該模擬器不能自動生成狀態報告再下發!請自行鍵入下面簡訊內容後,發送//狀態報告簡訊: 00000001DELIVRD031213505003121350501391xxx11381391xxx11381391xx11380001{CMPP_Msg_Content x = new CMPP_Msg_Content(Encoding.ASCII.GetBytes(response.Msg_Content));s = String.Format("收到狀態報告: /n{0}/n{1}", x.Stat, x.Dest_terminal_Id);}}else if (header.Command_Id == CMPP_Command_Id.CMPP_QUERY_RESP){CMPP_QUERY_RESP response = new CMPP_QUERY_RESP(bytes);s = String.Format("CMPP_QUERY_RESP: {0},{1}", response.Time, response.Query_Code);}else if (header.Command_Id == CMPP_Command_Id.CMPP_SUBMIT_RESP){CMPP_SUBMIT_RESP response = new CMPP_SUBMIT_RESP(bytes);s = String.Format("CMPP_SUBMIT_RESP Msg_Id: {0}, Result: {1}", response.Msg_Id, response.Result);}else if (header.Command_Id == CMPP_Command_Id.CMPP_TERMINATE_RESP){s = String.Format("good bye");}

Console.WriteLine(s + "/n");

}

public void PrintHeader(MessageHeader Header){Console.WriteLine("Response: Sequence_Id: {0}!", Header.Sequence_Id);Console.WriteLine("Total_Length: {0}!", Header.Total_Length);Console.WriteLine("Command_Id: {0}!", Header.Command_Id);}}}


推薦閱讀:

職場人際交往心理趣談 – 飛信空間 – 中國移動飛信
移動套路深,變著法的給你升套餐。
中國移動,請給解釋一下:不限量=100G
中國移動什麼時候會發下dd牌照?
一個套餐飛享粵港澳三地,廣東移動率先打破藩籬

TAG:中國 | 中國移動 | 客戶端 | 簡訊 | 客戶 | 實現 | 移動 |