短信程序:基于 CMPP3.0 協(xié)議 SP 端的實(shí)現(C#) 最近一段是時(shí)間項目可能需要提供短信功能,客戶(hù)作為一個(gè) SP 端提供短信業(yè)務(wù);網(wǎng)上搜索了一番,找到了比較不錯的 CMPP30 類(lèi)的代碼,該代碼基本實(shí)現了 CMPP3.0 協(xié)議中的短信收發(fā)、網(wǎng)絡(luò )重連等功能。本人將其重新改造,提供了同步發(fā)送、異步發(fā)送的支持(原先版本的異步發(fā)送并非標準的 .NET 異步發(fā)送模式,這部分代碼是一個(gè)異步操作實(shí)現的“范本”,可供大家參考),增加了對 PROVISION 接口的支持。 本人已將這些代碼打包為一個(gè) RAR 文件,稍后會(huì )上傳到 Internet 供大家交流、學(xué)習;下面將對這版 CMPP30 類(lèi)的 API 進(jìn)行簡(jiǎn)要介紹: 1)用于收發(fā)短信 CMPP30 類(lèi)的 API: Code 1/**//// <summary> 2/// CMPP30 短信網(wǎng)關(guān)通訊組件(供 SP 使用)。 3/// </summary> 4public class CMPP30 5{ 6 7 屬性#region 屬性 8 /**//// <summary> 9 /// SMS 事件。 10 /// </summary> 11 public event EventHandler<SMSEventArgs> SMS; 12 #endregion 13 14 構造函數#region 構造函數 15 /**//// <summary> 16 /// 初始化 <see cref="CMPP30"/> 類(lèi)新實(shí)例。 17 /// </summary> 18 public CMPP30(string spid, string password, string address, int port); 19 #endregion 20 21 公有方法#region 公有方法 22 /**//// <summary> 23 /// 啟動(dòng) CMPP30 服務(wù)。 24 /// </summary> 25 public void Start(); 26 /**//// <summary> 27 /// 發(fā)送短信。 28 /// </summary> 29 /// /// <param name="text"> 30 /// 信息內容。 31 /// </param> 32 /// <param name="encoding"> 33 /// 信息編碼。 34 /// </param> 35 /// <param name="sourceID"> 36 /// SP的服務(wù)代碼,將顯示在最終用戶(hù)手機上的短信主叫號碼。 37 /// </param> 38 /// <param name="destinations"> 39 /// 接收短信的電話(huà)號碼列表。 40 /// </param> 41 /// <param name="serviceID"> 42 /// 業(yè)務(wù)標識(如:woodpack)。 43 /// </param> 44 /// <param name="needReport"> 45 /// 是否要求返回狀態(tài)報告。 46 /// </param> 47 /// <param name="feeType"> 48 /// 資費類(lèi)別。 49 /// </param> 50 /// <param name="feeUserType"> 51 /// 計費用戶(hù)。 52 /// </param> 53 /// <param name="feeUser"> 54 /// 被計費的號碼(feeUserType 值為 FeeUser 時(shí)有效)。 55 /// </param> 56 /// <param name="realUser"> 57 /// 被計費號碼的真實(shí)身份(“真實(shí)號碼”或“偽碼”)。 58 /// </param> 59 /// <param name="informationFee"> 60 /// 信息費(以“分”為單位,如:10 分代表 1角)。 61 /// </param> 62 /// <param name="linkID"> 63 /// 點(diǎn)播業(yè)務(wù)的 LinkID。 64 /// </param> 65 public CMPP_SUBMIT_RESP Send( 66 string text, 67 CEncoding encoding, 68 string sourceID, 69 string[] destinations, 70 string serviceID, 71 bool needReport, 72 FeeType feeType, 73 FeeUserType feeUserType, 74 string feeUser, 75 bool realUser, 76 int informationFee, 77 string linkID); 78 /**//// <summary> 79 /// 發(fā)送短信。 80 /// </summary> 81 public CMPP_SUBMIT_RESP Send(CMPP_SUBMIT submit); 82 /**//// <summary> 83 /// 開(kāi)始異步發(fā)送短信。 84 /// </summary> 85 /// <param name="text"> 86 /// 信息內容。 87 /// </param> 88 /// <param name="encoding"> 89 /// 信息編碼。 90 /// </param> 91 /// <param name="sourceID"> 92 /// SP的服務(wù)代碼,將顯示在最終用戶(hù)手機上的短信主叫號碼。 93 /// </param> 94 /// <param name="destinations"> 95 /// 接收短信的電話(huà)號碼列表。 96 /// </param> 97 /// <param name="serviceID"> 98 /// 業(yè)務(wù)標識(如:woodpack)。 99 /// </param> 100 /// <param name="needReport"> 101 /// 是否要求返回狀態(tài)報告。 102 /// </param> 103 /// <param name="feeType"> 104 /// 資費類(lèi)別。 105 /// </param> 106 /// <param name="feeUserType"> 107 /// 計費用戶(hù)。 108 /// </param> 109 /// <param name="feeUser"> 110 /// 被計費的號碼(feeUserType 值為 FeeUser 時(shí)有效)。 111 /// </param> 112 /// <param name="realUser"> 113 /// 被計費號碼的真實(shí)身份(“真實(shí)號碼”或“偽碼”)。 114 /// </param> 115 /// <param name="informationFee"> 116 /// 信息費(以“分”為單位,如:10 分代表 1角)。 117 /// </param> 118 /// <param name="linkID"> 119 /// 點(diǎn)播業(yè)務(wù)的 LinkID。 120 /// </param> 121 /// <param name="callback"> 122 /// 異步回調函數。 123 /// </param> 124 /// <param name="asyncState"> 125 /// 傳遞給異步回調函數的參數。 126 /// </param> 127 public IAsyncResult BeginSend( 128 string text, 129 CEncoding encoding, 130 string sourceID, 131 string[] destinations, 132 string serviceID, 133 bool needReport, 134 FeeType feeType, 135 FeeUserType feeUserType, 136 string feeUser, 137 bool realUser, 138 int informationFee, 139 string linkID, 140 AsyncCallback callback, 141 object asyncState); 142 /**//// <summary> 143 /// 開(kāi)始異步發(fā)送短信。 144 /// </summary> 145 public IAsyncResult BeginSend( 146 CMPP_SUBMIT submit, 147 AsyncCallback cb, 148 object asyncState); 149 /**//// <summary> 150 /// 結束異步發(fā)送短信。 151 /// </summary> 152 public CMPP_SUBMIT_RESP EndSend(IAsyncResult ar); 153 /**//// <summary> 154 /// 停止 CMPP30 服務(wù)。 155 /// </summary> 156 public void Stop(); 157 #endregion 158 159}CMPP30 類(lèi) API
這個(gè)類(lèi)是核心類(lèi),我的代碼注釋很清楚,所以就不再贅述;需要注意一下的就是 Send、BeginSend、EndSend 是符合 .NET 框架標準的異步操
作模式;與網(wǎng)上的 CMPP30 類(lèi)不用的是 Send 函數要求傳入 CMPP_SUBMIT 數據包并返回一個(gè) CMPP_SUBMIT_RESP 包,這有利于調用者得到
由 ISMG 服務(wù)器返回的 MsgID 字段,否則調用者只能通過(guò) SMS 事件得到 CMPP_SUBMIT_RESP 包,但是僅僅有這個(gè)包是不能與其相對應的
CMPP_SUBMIT 進(jìn)行匹配的。
另外說(shuō)一下,所有與 ISMG 的交互都會(huì )導致 SMS 事件的引發(fā),該事件參數中會(huì )提供一個(gè) SMS_EVENT 枚舉供事件處理程序使用,詳細信息請參
考 SMS_EVENT 的代碼。
最后對使用我代碼的朋友說(shuō)一下,Start 與 Stop 這兩個(gè)函數只能調用一次。如果你的程序中調用 Stop 停止了 CMPP30 服務(wù),則必須重新實(shí)例
化一個(gè)新的 CMPP30 對象來(lái)啟動(dòng)該服務(wù)。
2)對 PROVISION 正向訂購/取消接口的支持: 根據 MISC1.6 的描述,對 PROVISION 接口的實(shí)現應該采用基于 SOAP 協(xié)議的 WEB 服務(wù)技術(shù),我這里提供了一個(gè) Provision 抽象類(lèi),該類(lèi)繼 承自 System.Web.Services.WebService。呵呵,看出來(lái)了吧,我的想法就是讓 asmx 頁(yè)的后臺類(lèi)繼承 Provision 類(lèi)。該類(lèi)封裝了 PROVISION 接 口中的 SyncOrderRelationReq 和 SyncOrderRelationResp 包的實(shí)現,將這對“發(fā)送/響應”包的收發(fā)變?yōu)椤耙淮螌?WEB 服務(wù)函數的調用”,當接 收到 SyncOrderRelationReq 時(shí)就調用 Provision 類(lèi)中的 SyncOrderRelationReq 函數(WebMethod),并將該函數返回值轉變?yōu)橐粋€(gè) SyncOrderRelationResp 包返回給移動(dòng)的服務(wù)器。API 代碼如下: Code 1/**//// <summary> 2/// 正向(反向)同步 PROVISION 接口服務(wù)。 3/// </summary> 4[WebService(Namespace = "http://www.monternet.com/dsmp/schemas/")] 5[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)] 6public abstract class Provision : System.Web.Services.WebService 7{ 8 9 屬性#region 屬性 10 /**//// <summary> 11 /// SOAP 消息編號(DSMG 調用該 WEB 服務(wù)時(shí)需要設置該信息)。 12 /// </summary> 13 [EditorBrowsable(EditorBrowsableState.Never)] 14 public TransactionID TransactionID; 15 #endregion 16 17 保護方法#region 保護方法 18 /**//// <summary> 19 /// MISC 因為某種情況(如:用戶(hù)通過(guò)手機短信的方式執行了某操作)更新了用戶(hù)訂購關(guān)系(包括:訂購、取消、暫停、激活)的時(shí)候,通過(guò)此函數發(fā)起和 SP 的更新訂購關(guān)系的交互。 20 /// </summary> 21 /// <param name="id"> 22 /// 消息編號。 23 /// </param> 24 /// <param name="sendAddr"> 25 /// 發(fā)送方的地址。 26 /// </param> 27 /// <param name="destAddr"> 28 /// 接收方的地址。 29 /// </param> 30 /// <param name="feeUserID"> 31 /// 計費用戶(hù)標識。 32 /// </param> 33 /// <param name="destUserID"> 34 /// 使用用戶(hù)標識(當使用用戶(hù)和計費用戶(hù)為同一用戶(hù)的時(shí)候,FeeUser_ID 和 DestUser_ID 的值相同)。 35 /// </param> 36 /// <param name="linkID"> 37 /// 臨時(shí)訂購關(guān)系的事務(wù) ID。 38 /// </param> 39 /// <param name="actionID"> 40 /// 服務(wù)狀態(tài)管理動(dòng)作代碼(1:開(kāi)通服務(wù);2:停止服務(wù);3:激活服務(wù);4:暫停服務(wù))。 41 /// </param> 42 /// <param name="actionReasonID"> 43 /// 產(chǎn)生服務(wù)狀態(tài)管理動(dòng)作原因的代碼(1:用戶(hù)發(fā)起行為;2:Admin&1860發(fā)起行為;3:Boss停機;4:Boss開(kāi)機;5:Boss過(guò)戶(hù);6:Boss銷(xiāo)戶(hù);7:Boss改號;8:扣費失敗導致的服務(wù)取消;9:其他)。 44 /// </param> 45 /// <param name="spid"> 46 /// SP 的企業(yè)代碼。 47 /// </param> 48 /// <param name="serviceID"> 49 /// 業(yè)務(wù)標識,是數字、字母和符號的組合(長(cháng)度為 10,SP的業(yè)務(wù)類(lèi)型,數字、字母和符號的組合,由SP自定,如圖片傳情可定為T(mén)PCQ,股票查詢(xún)可定義為11),也叫做計費代碼。 50 /// </param> 51 /// <param name="accessMode"> 52 /// 服務(wù)的訪(fǎng)問(wèn)方式(1:WEB;2:WAP;3:SMS)。 53 /// </param> 54 /// <param name="featureStr"> 55 /// 服務(wù)訂購參數(base64加密),內容是長(cháng)號碼+空格+用戶(hù)發(fā)送內容。 56 /// </param> 57 /// <param name="hResult"> 58 /// 返回值(0:成功;1:未知錯誤;2-99:保留;4000:無(wú)效的msgtype;4001:無(wú)效的action_id;4002:無(wú)效的action_reasonid;4003:無(wú)效的SP ID;4004:無(wú)效的serviceID;4005:無(wú)效的pseudocode;4006:無(wú)效的accessmode;4007:MISC 同步開(kāi)通服務(wù),但SP 端已存在訂購關(guān)系,且狀態(tài)為開(kāi)通;4008:MISC 同步開(kāi)通服務(wù),且SP 端不存在訂購關(guān)系,但開(kāi)通服務(wù)失??;4009:MISC 同步開(kāi)通服務(wù),但SP 端已存在訂購關(guān)系, 且狀態(tài)為暫停;4010:MISC 同步停止服務(wù), 且SP 端存在訂購關(guān)系, 但取消服務(wù)失??;4011:MISC 同步停止服務(wù), 但SP 端不存在訂購關(guān)系;4012:MISC 同步暫停服務(wù), 且SP 端存在訂購關(guān)系, 但暫停服務(wù)失??;4013:MISC 同步暫停服務(wù), 但SP 端不存在訂購關(guān)系;4014:MISC 同步暫停服務(wù), 但SP 端已存在訂購關(guān)系, 且狀態(tài)為暫停;4015:MISC 同步激活服務(wù), 但SP 端已存在訂購關(guān)系, 且狀態(tài)為開(kāi)通;4016:MISC 同步激活服務(wù), 但SP 端不存在訂購關(guān)系;4017:MISC 同步激活服務(wù), 且SP 端存在訂購關(guān)系, 但激活服務(wù)失??;9000:系統磁盤(pán)讀寫(xiě)錯誤;9001:網(wǎng)絡(luò )異常;9002:網(wǎng)絡(luò )錯誤;9003:業(yè)務(wù)網(wǎng)關(guān)忙,業(yè)務(wù)網(wǎng)關(guān)緩存;9004:業(yè)務(wù)網(wǎng)關(guān)忙,并且業(yè)務(wù)網(wǎng)關(guān)緩沖區滿(mǎn),MISC 緩存,并暫時(shí)不要發(fā)送消息,等待一段時(shí)間重試;9005:MISC 忙,MISC 緩存;9006:MISC 忙,并且MISC 緩沖區滿(mǎn),業(yè)務(wù)網(wǎng)關(guān)緩存,并暫時(shí)不要發(fā)送消息,等待一段時(shí)間重試;9007:業(yè)務(wù)網(wǎng)關(guān)超過(guò)限制的流量;9008:MISC 異常,并不可用;9009:業(yè)務(wù)網(wǎng)關(guān)異常,并不可用;9010:該業(yè)務(wù)網(wǎng)關(guān)沒(méi)有權限調用該接口消息;9011:MISC 沒(méi)有權限發(fā)送該接口消息給業(yè)務(wù)網(wǎng)關(guān);9012:版本不支持;9013:消息類(lèi)型不對,系統不支持;9014:驗證錯誤,無(wú)法解析SOAP 和XML 結構、缺少必須存在的字段,或者消息,格式不正確;9015:拒絕消息,服務(wù)器無(wú)法完成請求的服務(wù))。 59 /// </param> 60 protected abstract void OnSyncOrderRelationReq( 61 string id, 62 AddressInfo sendAddr, 63 AddressInfo destAddr, 64 UserID feeUserID, 65 UserID destUserID, 66 string linkID, 67 int actionID, 68 int actionReasonID, 69 string spid, 70 string serviceID, 71 int accessMode, 72 byte[] featureStr, 73 out int hResult); 74 #endregion 75 76 公有方法#region 公有方法 77 /**//// <summary> 78 /// MISC 因為某種情況(如:用戶(hù)通過(guò)手機短信的方式執行了某操作)更新了用戶(hù)訂購關(guān)系(包括:訂購、取消、暫停、激活)的時(shí)候,通過(guò)此函數發(fā)起和 SP 的更新訂購關(guān)系的交互。 79 /// </summary> 80 /// <param name="Version"> 81 /// 接口消息的版本號,目前接口消息的版本都為“1.5.0” 82 /// </param> 83 /// <param name="MsgType"> 84 /// 消息類(lèi)型。 85 /// </param> 86 /// <param name="Send_Address"> 87 /// 發(fā)送方的地址。 88 /// </param> 89 /// <param name="Dest_Address"> 90 /// 接收方的地址。 91 /// </param> 92 /// <param name="FeeUser_ID"> 93 /// 計費用戶(hù)標識。 94 /// </param> 95 /// <param name="DestUser_ID"> 96 /// 使用用戶(hù)標識(當使用用戶(hù)和計費用戶(hù)為同一用戶(hù)的時(shí)候,FeeUser_ID 和 DestUser_ID 的值相同)。 97 /// </param> 98 /// <param name="LinkID"> 99 /// 臨時(shí)訂購關(guān)系的事務(wù) ID。 100 /// </param> 101 /// <param name="ActionID"> 102 /// 服務(wù)狀態(tài)管理動(dòng)作代碼(1:開(kāi)通服務(wù);2:停止服務(wù);3:激活服務(wù);4:暫停服務(wù))。 103 /// </param> 104 /// <param name="ActionReasonID"> 105 /// 產(chǎn)生服務(wù)狀態(tài)管理動(dòng)作原因的代碼(1:用戶(hù)發(fā)起行為;2:Admin&1860發(fā)起行為;3:Boss停機;4:Boss開(kāi)機;5:Boss過(guò)戶(hù);6:Boss銷(xiāo)戶(hù);7:Boss改號;8:扣費失敗導致的服務(wù)取消;9:其他)。 106 /// </param> 107 /// <param name="SPID"> 108 /// SP 的企業(yè)代碼。 109 /// </param> 110 /// <param name="SPServiceID"> 111 /// 業(yè)務(wù)標識,是數字、字母和符號的組合(長(cháng)度為 10,SP的業(yè)務(wù)類(lèi)型,數字、字母和符號的組合,由SP自定,如圖片傳情可定為T(mén)PCQ,股票查詢(xún)可定義為11),也叫做計費代碼。 112 /// </param> 113 /// <param name="AccessMode"> 114 /// 服務(wù)的訪(fǎng)問(wèn)方式(1:WEB;2:WAP;3:SMS)。 115 /// </param> 116 /// <param name="FeatureStr"> 117 /// 服務(wù)訂購參數(base64加密),內容是長(cháng)號碼+空格+用戶(hù)發(fā)送內容。 118 /// </param> 119 /// <param name="hRet"> 120 /// 返回值(0:成功;1:未知錯誤;2-99:保留;4000:無(wú)效的msgtype;4001:無(wú)效的action_id;4002:無(wú)效的action_reasonid;4003:無(wú)效的SP ID;4004:無(wú)效的serviceID;4005:無(wú)效的pseudocode;4006:無(wú)效的accessmode;4007:MISC 同步開(kāi)通服務(wù),但SP 端已存在訂購關(guān)系,且狀態(tài)為開(kāi)通;4008:MISC 同步開(kāi)通服務(wù),且SP 端不存在訂購關(guān)系,但開(kāi)通服務(wù)失??;4009:MISC 同步開(kāi)通服務(wù),但SP 端已存在訂購關(guān)系, 且狀態(tài)為暫停;4010:MISC 同步停止服務(wù), 且SP 端存在訂購關(guān)系, 但取消服務(wù)失??;4011:MISC 同步停止服務(wù), 但SP 端不存在訂購關(guān)系;4012:MISC 同步暫停服務(wù), 且SP 端存在訂購關(guān)系, 但暫停服務(wù)失??;4013:MISC 同步暫停服務(wù), 但SP 端不存在訂購關(guān)系;4014:MISC 同步暫停服務(wù), 但SP 端已存在訂購關(guān)系, 且狀態(tài)為暫停;4015:MISC 同步激活服務(wù), 但SP 端已存在訂購關(guān)系, 且狀態(tài)為開(kāi)通;4016:MISC 同步激活服務(wù), 但SP 端不存在訂購關(guān)系;4017:MISC 同步激活服務(wù), 且SP 端存在訂購關(guān)系, 但激活服務(wù)失??;9000:系統磁盤(pán)讀寫(xiě)錯誤;9001:網(wǎng)絡(luò )異常;9002:網(wǎng)絡(luò )錯誤;9003:業(yè)務(wù)網(wǎng)關(guān)忙,業(yè)務(wù)網(wǎng)關(guān)緩存;9004:業(yè)務(wù)網(wǎng)關(guān)忙,并且業(yè)務(wù)網(wǎng)關(guān)緩沖區滿(mǎn),MISC 緩存,并暫時(shí)不要發(fā)送消息,等待一段時(shí)間重試;9005:MISC 忙,MISC 緩存;9006:MISC 忙,并且MISC 緩沖區滿(mǎn),業(yè)務(wù)網(wǎng)關(guān)緩存,并暫時(shí)不要發(fā)送消息,等待一段時(shí)間重試;9007:業(yè)務(wù)網(wǎng)關(guān)超過(guò)限制的流量;9008:MISC 異常,并不可用;9009:業(yè)務(wù)網(wǎng)關(guān)異常,并不可用;9010:該業(yè)務(wù)網(wǎng)關(guān)沒(méi)有權限調用該接口消息;9011:MISC 沒(méi)有權限發(fā)送該接口消息給業(yè)務(wù)網(wǎng)關(guān);9012:版本不支持;9013:消息類(lèi)型不對,系統不支持;9014:驗證錯誤,無(wú)法解析SOAP 和XML 結構、缺少必須存在的字段,或者消息,格式不正確;9015:拒絕消息,服務(wù)器無(wú)法完成請求的服務(wù))。 121 /// </param> 122 [WebMethod] 123 [SoapHeader("TransactionID", Direction = SoapHeaderDirection.InOut)] 124 [SoapDocumentMethod("sim.SyncOrderRelation", RequestElementName = "SyncOrderRelationReq", ResponseElementName = "SyncOrderRelationResp")] 125 [return: System.Xml.Serialization.SoapElementAttribute("return")] 126 [EditorBrowsable(EditorBrowsableState.Never)] 127 public void SyncOrderRelationReq( 128 ref string Version, 129 ref string MsgType, 130 AddressInfo Send_Address, 131 AddressInfo Dest_Address, 132 UserID FeeUser_ID, 133 UserID DestUser_ID, 134 string LinkID, 135 int ActionID, 136 int ActionReasonID, 137 string SPID, 138 string SPServiceID, 139 int AccessMode, 140 byte[] FeatureStr, 141 out int hRet) 142 { 143 144 Version = "1.5.0"; 145 MsgType = "SyncOrderRelationResp"; 146 147 OnSyncOrderRelationReq( 148 TransactionID == null ? null : TransactionID.ID, 149 Send_Address, 150 Dest_Address, 151 FeeUser_ID, 152 DestUser_ID, 153 LinkID, 154 ActionID, 155 ActionReasonID, 156 SPID, SPServiceID, 157 AccessMode, 158 FeatureStr, 159 out hRet); 160 } 161 #endregion 162 163}Provision 類(lèi)的 API
注意:asmx 頁(yè)還是需要使用者自己建的,只需要將 asmx 的后臺代碼類(lèi)繼承 Provision 類(lèi),并實(shí)現抽象函數 OnSyncOrderRelationReq 即
可,在該抽象函數內,記錄手機用戶(hù)訂購(或取消)業(yè)務(wù)的信息。
3)對 PROVISION 反向訂購/取消接口的支持: 最后再簡(jiǎn)要地說(shuō)一下關(guān)于對反向訂購/取消的支持,我的實(shí)現就是對 dsmp.wsdl 這個(gè) WEB 服務(wù)的一個(gè)簡(jiǎn)單封裝。該 WEB 在移動(dòng)的服務(wù)器上發(fā) 布。需要說(shuō)明的是:根據反向訂購/取消的業(yè)務(wù)流程,在這個(gè)過(guò)程中會(huì )執行正向訂購/取消的那個(gè) WEB 服務(wù)函數,因為反向訂購/取消業(yè)務(wù)也會(huì )要求SP 接收一個(gè) SyncOrderRelationReq 包并返回與其相應的 SyncOrderRelationResp 包。所以 PROVISION 實(shí)現的關(guān)鍵還是在 Provision 類(lèi)。 下面是本文代碼的下載鏈接:http://files.cnblogs.com/arcadiaray/CMPP30.rar