国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
CMPP2.0 協(xié)議SP端的·NET開發(fā)

內(nèi)容簡介:本文介紹了CMPP2.0協(xié)議SP.net實現(xiàn)需要注意的問題,并提供解決方案和參考意見,對CMPP協(xié)議做一個解讀參考。

 

關(guān)鍵字CMPP 2.0 SMS ISMG Socket 線程 線程同步 .Net事件模型

 

一、CMPP協(xié)議簡介

中國移動通信互聯(lián)網(wǎng)短信網(wǎng)關(guān)接口協(xié)議(China Mobile Peer to Peer CMPP),是中國移動夢網(wǎng)內(nèi)部各SMS參與節(jié)點相互交換SMS的官方協(xié)議。作為夢網(wǎng)的參與方,移動夢網(wǎng)的增值服務(wù)商(Service Provider SP )要按照此協(xié)議規(guī)范實現(xiàn)SP的部分,才可以將自己的短信通過移動的GSM網(wǎng)絡(luò)的數(shù)據(jù)通道傳輸?shù)阶罱K手機用戶上。

實際上,協(xié)議規(guī)范了3個方面的內(nèi)容:

SP與移動的互聯(lián)網(wǎng)短信網(wǎng)關(guān)(Internet Short Message Gateway,ISMG)之間的接口協(xié)議

。ISMG之間的接口協(xié)議(譬如移動各省、市之間的短信息交換通過ISMG之間進行)

。ISMG與匯接網(wǎng)關(guān)(Gateway Name Server GNS,類似互聯(lián)網(wǎng)上的DNS服務(wù)器)之間的接口協(xié)議,譬如跨省之類的短信需要GNS的幫助指出當前ISMG該如何傳遞短信。

其中,后二方面屬于移動短信息系統(tǒng)內(nèi)部實現(xiàn),對于SP來講大概可以“透明”來看待,只要實現(xiàn)了SPISMG的正確交互,就可以實現(xiàn)接入移動夢網(wǎng)短信系統(tǒng)。我們關(guān)心的只是SP端的開發(fā)細節(jié)。

 

二、CMPP交互模式

從手機用戶角度講,按短信的發(fā)起/接收路徑來講,有兩個叫法:

MT(Short Message Mobile Terminated, SMMT),短信接收,短信從SP發(fā)送到手機用戶。

MO (Short Message Mobile Originate,SMMO),短信發(fā)送,短信從手機用戶端發(fā)送到目標SP。

這兩類短信交互,從SP端來看,都是屬于Socket傳輸應用,CMPP的協(xié)議是以TCP/IP協(xié)議作為底層承載協(xié)議的,屬于TCP/IP協(xié)議棧之上的應用。

SPISMG的交互連接分長連接短連接。

所謂短連接,就是一次連接,傳輸一個消息,然后等待回復后拆除連接,顯然,效率很低,所以,基本上不被考慮(實際應用移動也不允許SP采用短連接,只是不明白移動為什么還要寫入文檔? ISMG間會需要?)

所謂長連接,就是SP建立同ISMG連接,然后不斷將數(shù)據(jù)包(一個個CMPP消息)發(fā)送到ISMG,此處發(fā)送不必等待某條消息的ISMG回應消息返回,就接著發(fā)送下一個消息。同時,等待ISMG返回信息或者等待ISMG發(fā)送給SP的消息。發(fā)送同接收消息不是一定要同步的,實際采用異步(同時也時雙工)模式。從效率上,顯然,必須全雙工的異步模式才能夠滿足實際應用需求。

如下圖(摘自CMPP2.0官方文檔)所示,演示了長連接模式數(shù)據(jù)傳輸過程:

 

 

 

 

 

 

 


三、SP端開發(fā)

1.         消息分類

首先,圖中的CMPP消息有很多種,SPISMG之間交流這些消息。大體上這些消息發(fā)出后,對方往往需要回復一個應答(RESP)類消息。注意,這些消息大多具有方向性,也就是說只能夠從一端到另一端,而不可反方向進行,有些(少數(shù))則可兩端都能夠發(fā)出。以下信息主要來源于移動的文檔,但針對大家易混淆或源文檔解釋不夠詳細做了明確和補充。具體見下表:

       消息名

傳遞方向

解釋說明

CMPP­_CONNECT

SP---àISMG

CMPP_CONNECT操作的目的是SPISMG注冊作為一個合法SP身份,此消息需要向ISMG發(fā)出驗證信息,驗證方式采用md5加密密碼方式,若注冊成功后即建立了應用層的連接(否則ISMG會立即斷開Socket),此后SP可以通過此ISMG接收和發(fā)送短信。

ISMGCMPP_CONNECT_RESP消息響應SP的請求。具體的算法實現(xiàn)參考CMPP2.0文檔和本文附件代碼。

CMPP_CONNECT_RESP

SPß---ISMG

ISMGCMPP_CONNECT消息的回復(無論是否驗證成功);如果未通過,會在消息中包含參考信息,但ISMG會立即斷開連接。

CMPP­_ACTIVE_TEST

SPßàISMG

這個消息通信雙方都可以發(fā)出,目的是在沒有其他消息發(fā)送時,保持雙方的通信鏈路的連接,避免系統(tǒng)認為通信通道已經(jīng)關(guān)閉。每一個收到此消息的實體應當返回CMPP_ACTIVE_TEST_RESP消息,以“禮節(jié)性”表示自己的還在通信,維持數(shù)據(jù)連接有效性。

不過,據(jù)網(wǎng)友交流,有些廠家實現(xiàn)的ISMG,僅僅靠自己發(fā)出此消息等待SP回答CMPP_ACTIVE_TEST_RESP來確定數(shù)據(jù)鏈路的有效性,而忽略SPCMPP_ACTIVE_TEST消息(有些霸道吧?)這個值得注意,不要僅僅實現(xiàn)發(fā)送而不響應此消息,避免數(shù)據(jù)連接失效。

CMPP_ACTIVE_TEST_RESP

SPßàISMG

對通信的另一端的CMPP_ACTIVE_TEST消息的回復。作用參考CMPP_ACTIVE_TEST的解釋。

CMPP­_SUBMIT

SP---àISMG

在正確建立了數(shù)據(jù)連接后,SPISMG發(fā)送一個SMS數(shù)據(jù)包。本消息需要仔細研究。接收到此消息后,ISMG需要以CMPP_SUBMIT_RESP消息作為回答。如果在一定時間時間內(nèi)(移動給出的參考值60秒)內(nèi)未得到消息回應,那么SP需要重新發(fā)送此數(shù)據(jù)包,以確保消息得到投遞。如果重發(fā)達到3次后仍然得不到回應,SP端應該考慮可能ISMG已經(jīng)失效,應當停止發(fā)送此短消息。

CMPP­_SUBMIT_RESP

SPß---ISMG

該消息由ISMG發(fā)送給SP,同時返回一個“收條”(CMPP_SUBMIT消息的ISMG端的標示MSGID)SP,表示“我ISMG已經(jīng)確認收到你這條消息了”。收到此消息后,SP需要保留此“收條”,因為后面ISMG會最終報告本消息是否正確發(fā)送到用戶手機。那個報告就是以此消息的“收條”作為確認那一條消息的。

CMPP_QUERY

SP---àISMG

這個查詢不是查詢單條消息的,是查詢SP發(fā)送給ISMG的短信的業(yè)務(wù)情況??梢圆榭傆嫈?shù),還可以分類查詢。(基本就是發(fā)起對移動sms業(yè)務(wù)數(shù)據(jù)庫的查詢統(tǒng)計)

CMPP_QUERY_RESP

SPß---ISMG

ISMG將查詢的數(shù)據(jù)返回給SP。

CMPP_CANCEL

SP---àISMG

SP發(fā)起的取消某條消息的命令消息,其中包含了之前已經(jīng)發(fā)送給ISMG消息的“收條”以便ISMG可以確定是那一條消息。如果消息已經(jīng)發(fā)送給用戶了,那么此消息/命令會無效,ISMG返回失敗。

CMPP_CANCEL_RES

SPß---ISMG

ISMG返回的對CMPP_CANCEL的回復,并告知是否刪除成功。

CMPP_DELIVER

SPß---ISMG

當有MO或者狀態(tài)報告時,ISMG發(fā)送此消息。注意,此消息的數(shù)據(jù)可以是用戶手機發(fā)送給SP的消息,也可是對于之前SP發(fā)送到ISMG的短信的最終狀態(tài)的回復,報告短信的最終狀態(tài)。

CMPP_DELIVER_RESP

SP---àISMG

SP禮節(jié)性的回復告知收到CMPP_DELIVER消息。要指出SP報告的CMPP_DELIVER消息的MSGID,以便ISMG知道那一條消息SP已經(jīng)確認收到。

CMPP_TERMINAT

SPßàISMG

SPISMG都可以主動發(fā)消息給對方,自己這端由于某種原因需要終止當前的數(shù)據(jù)連接。終止后,要經(jīng)過重新Connection(驗證)之后才可以(進入事務(wù)階段)發(fā)送SMS數(shù)據(jù)消息。

CMPP­_TERMINATE_RES

SPßàISMG

通知對方,本端已經(jīng)最好撤除連接的準備。

                    

2.         交互階段

整個CMPP協(xié)議交互分為驗證、事務(wù)兩個階段。驗證階段,發(fā)送CMPP_CONNECTION消息進行驗證,通過驗證后(必須要通過才)進入CMPP事務(wù)階段,可以發(fā)送短信數(shù)據(jù)了。上表中的CMPP_CONNECTION以下的消息都屬于事務(wù)階段的消息。

 

3.         消息數(shù)據(jù)結(jié)構(gòu)

每一個消息包含 消息頭 消息體兩個部分,頭固定長度為12字節(jié),其他消息長度各異,但是同一類型消息的長度是固定的。所有消息的各個字段基本上僅有3種類型:Unsigned Integer (無符號整型)  、Integer(整型)、Octet String(字符串),每種類型具體長度不定,網(wǎng)絡(luò)字節(jié)順序。

1、  消息頭(3Unsigned Integer字段組成)

4字節(jié)的Total_Length Unsigned Integer),包含了此消息的總計(包括了頭部分)長度。

4字節(jié)的Command_IdUnsigned Integer),指明了此消息到底是什么消息,就是上表中消息的枚舉值。應用程序根據(jù)此值確定本數(shù)據(jù)包到底是什么消息,從而可以按照確定的消息類型,解析余下的消息體。

4字節(jié)的Sequence_IdUnsigned Integer),指明了此數(shù)據(jù)包在發(fā)送此消息端的唯一編號。這個唯一編號,實際上可以看作流水操作編號。因為分析到交互模式我們看到,SP發(fā)送數(shù)據(jù)到ISMG,不是每發(fā)送一個就停下來等待ISMG的回復,而是“一下子”發(fā)送多個數(shù)據(jù)包過去,然后等待ISMG的回應。然而,怎么知道回應的消息是到底對應之前發(fā)送過去的消息中的那一條呢?本字段就是解決此難題。SP按照編號發(fā)送消息過去,等待ISMG的回應一般情形下回應消息數(shù)據(jù)結(jié)構(gòu)都有表明本消息回應的是SP發(fā)出的哪一條消息,這個對應就是依靠Sequence_Id。它并不要求一定要嚴格唯一,但是在給定的一段時間內(nèi),必須唯一(基本上只要SP發(fā)送過去的消息中沒有重復就行了)。如果是需要SP回答的消息,SP也必須將ISMG發(fā)送過來的消息的Sequence_Id填入相應字段,表明這是某個消息的回應。SP端和ISMGSequence_ID都沒有確定具體的算法。SP可以(但不推薦)采用數(shù)據(jù)庫的唯一Id作為此值。

 

2、消息體。消息體長度根據(jù)消息不同,長度不一。其他的參考移動的文檔《中國移動通信互聯(lián)網(wǎng)短信網(wǎng)關(guān)接口協(xié)議(China Mobile Peer to Peer, CMPP)V2.0)》,這里著重講講2個重要消息的消息體數(shù)據(jù)結(jié)構(gòu):

       CMPP­_SUBMIT的消息體:

字段名

長度(byte)

類型

描述

Msg_Id

8

Unsigned Integer

信息標識,應該由SP側(cè)ISMG本身產(chǎn)生,本處填空,供ISMG傳輸時使用。SP提交時候應當留空。

Pk_total

1

Unsigned Integer

相同Msg_Id的信息總條數(shù),從1開始。如果一條消息長度超多一條短信,可能需要分解成多條消息,那么實際上這多條消息屬于一條完整消息,所以可以根據(jù)此給分解得到的多條短信進行編號,那么總計需要編成多少條短信,此處就填寫多少。

 

Pk_number

1

Unsigned Integer

相同Msg_Id的信息序號,從1開始。編號決定消息的相對位置。

Registered_Delivery

1

Unsigned Integer

是否要求返回狀態(tài)確認報告:

0:不需要

1:需要

2:產(chǎn)生SMC話單(該類型短信僅供網(wǎng)關(guān)計費使用,不發(fā)送給目的終端)。

一般情況下,都需要確認報告。SMC話單也需要返回是否成功的報告。這條消息用于包月SMC時,當你發(fā)送消息給移動的ISMG,移動的計費系統(tǒng)會一次性扣除用戶的信息費,但是此消息不會送到用戶手機。但是注意,有的ISMG廠商(很可能是移動要求)實現(xiàn)此消息時候,如果你并沒有發(fā)送任何此包月類型的消息給用戶手機,是不發(fā)生扣費行為的。移動會認為這是屬于違規(guī)的“代收費”行為,會影響同移動的合作關(guān)系。

Msg_level

1

Unsigned Integer

信息級別,信息的優(yōu)先級。不過實際當中,感覺ISMG端并沒有區(qū)分優(yōu)先級。

Service_Id

10

Octet String

業(yè)務(wù)類型,是數(shù)字、字母和符號的組合。這個表示業(yè)務(wù)的字符串可以給發(fā)出的短信分類。通過此字段大約可以知道每個服務(wù)項目的業(yè)務(wù)量,有利于統(tǒng)計和計費以及結(jié)算。

Fee_UserType

1

Unsigned Integer

計費用戶類型字段

0:對目的終端MSISDN計費;

1:對源終端MSISDN計費;

2:對SP計費;

3:表示本字段無效,對誰計費參見Fee_terminal_Id字段。

Fee_terminal_Id

21

Unsigned Integer

被計費用戶的號碼(如本字節(jié)填空,則表示本字段無效,對誰計費參見Fee_UserType字段,本字段與Fee_UserType字段取0、12時互斥)

TP_pId

1

Unsigned Integer

GSM協(xié)議類型。詳細是解釋請參考GSM03.40中的9.2.3.9

TP_udhi

1

Unsigned Integer

GSM協(xié)議類型。詳細是解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊

Msg_Fmt

1

Unsigned Integer

信息格式

  0ASCII

  3:短信寫卡操作

  4:二進制信息

  8UCS2編碼

15:含GB漢字  

這個決定了Msg_Content字段的字節(jié)內(nèi)容應該按照什么編碼來解碼/編碼。

Msg_src

6

Octet String

信息內(nèi)容來源(SP的企業(yè)代碼),例如919000。

FeeType

2

Octet String

資費類別

01:對“計費用戶號碼”免費

02:對“計費用戶號碼”按條計信息費

03:對“計費用戶號碼”按包月收信息費

04:對“計費用戶號碼”的信息費封頂

05:對“計費用戶號碼”的收費是由SP實現(xiàn)。

通常值為02,注意這是一個字符串,并非整型。

FeeCode

6

Octet String

資費代碼(以分為單位),如:“0050”代表人民幣0.50元。

ValId_Time

17

Octet String

存活有效期,格式遵循SMPP3.3協(xié)議

At_Time

17

Octet String

定時發(fā)送時間,格式遵循SMPP3.3協(xié)議。這個字段可以讓短信在規(guī)定的時間給手機用戶。一般情況下不填,保留為空字符串。

Src_Id

21

Octet String

源號碼

SP的服務(wù)代碼或前綴為服務(wù)代碼的長號碼, 網(wǎng)關(guān)將該號碼完整的填到SMPP協(xié)議Submit_SM消息相應的source_addr字段,該號碼最終在用戶手機上顯示為短消息的主叫號碼。實際上就是服務(wù)代碼,可以是長號碼

DestUsr_tl

1

Unsigned Integer

接收信息的用戶數(shù)量(小于100個用戶),通常是1。移動是忌諱一條消息發(fā)給多個用戶的。

Dest_terminal_Id

21*DestUsr_tl

Octet String

接收短信的MSISDN號碼,一個類似字符串數(shù)組的結(jié)構(gòu)。受DestUsr_tl的約束,決定了本字段的長度。

Msg_Length

1

Unsigned Integer

信息長度(Msg_Fmt值為0時:<160個字節(jié);其它<=140個字節(jié))。如果是ASCII碼,可以達到160個英文字母。原因是因為英文字母僅占用7bit,而中文等雙字節(jié)代碼需要16位,同時每一個字節(jié)最高為都占用,所以最多140個字節(jié),也就是70個漢字。

Msg_Content

Msg_length

Octet String

信息內(nèi)容

Reserve

8

Octet String

保留

CMPP_SUBMIT消息長度是可變的,將SP端的消息發(fā)送給ISMG,ISMG將返回一個MSGIDSP標示此消息,之后(48小時以內(nèi),但一般最多幾分鐘內(nèi)就可),ISMG返回關(guān)于此消息的遞送報告。遞送報告同MO短消息是通過另外一個重要消息CMPP­_DELIVER來提交給SP的:

CMPP­_DELIVER的各個字段:

字段名

字節(jié)數(shù)

屬性

描述

Msg_Id

8

Unsigned Integer

信息標識

生成算法如下:

采用64位(8字節(jié))的整數(shù):

(1)時間(格式為MMDDHHMMSS,即月日時分秒):bit64~bit39,其中

bit64~bit61:月份的二進制表示;

bit60~bit56:日的二進制表示;

bit55~bit51:小時的二進制表示;

bit50~bit45:分的二進制表示;

bit44~bit39:秒的二進制表示;

(2)短信網(wǎng)關(guān)代碼:bit38~bit17,把短信網(wǎng)關(guān)的代碼轉(zhuǎn)換為整數(shù)填寫到該字段中。

(3)序列號:bit16~bit1,順序增加,步長為1,循環(huán)使用。

各部分如不能填滿,左補零,右對齊。

Dest_Id

21

Octet String

目的號碼

SP的服務(wù)代碼,一般4--6位,或者是前綴為服務(wù)代碼的長號碼;該號碼是手機用戶短消息的被叫號碼。

Service_Id

10

Octet String

業(yè)務(wù)類型,是數(shù)字、字母和符號的組合。

TP_pid

1

Unsigned Integer

GSM協(xié)議類型。詳細解釋請參考GSM03.40中的9.2.3.9

TP_udhi

1

Unsigned Integer

GSM協(xié)議類型。詳細解釋請參考GSM03.40中的9.2.3.23,僅使用1位,右對齊

Msg_Fmt

1

Unsigned Integer

信息格式

  0ASCII

  3:短信寫卡操作

  4:二進制信息

  8UCS2編碼

15:含GB漢字   

Src_terminal_Id

21

Octet String

源終端MSISDN號碼(狀態(tài)報告時填為CMPP_SUBMIT消息的目的終端號碼)

Registered_Delivery

1

Unsigned Integer

是否為狀態(tài)報告

0:非狀態(tài)報告(MO SMS

1:狀態(tài)報告

此字段決定了CMPP­_DELIVER消息到底是手機上行一條消息到SP還是ISMGSP報告之前發(fā)送的消息最終遞送狀態(tài)。

Msg_Length

1

Unsigned Integer

消息長度。是指Msg_Content字段的長度。

Msg_Content

Msg_length

Octet String

消息內(nèi)容。如果消息不是狀態(tài)報告,那么按照Msg_Fmt指示解碼為特定編碼的字符串內(nèi)容。

Reserved

8

Octet String

保留項

如果是報告,那么Msg_Content將按照狀態(tài)報告結(jié)構(gòu)來解釋:

字段名

字節(jié)數(shù)

屬性

描述

Msg_Id

8

Unsigned Integer

信息標識

SP提交短信(CMPP_SUBMIT)操作時,與SP相連的ISMG產(chǎn)生的Msg_Id。

這個MSGID實際上就是SP之前發(fā)送一個CMPP_SUBMIT消息之后的CMPP_SUBMIT_RESP消息中返回的關(guān)于CMPP_SUBMIT消息的ISMG編號.,根據(jù)此MSGID可以知道那條消息最終確定的遞送狀態(tài)。

Stat

7

Octet String

發(fā)送短信的應答結(jié)果,含義與SMPP協(xié)議要求中stat字段定義相同,詳見下面。SP根據(jù)該字段確定被報告的CMPP_SUBMIT消息的處理狀態(tài)。

Submit_time

10

Octet String

YYMMDDHHMMYY為年的后兩位00-99,MM01-12DD01-31,HH00-23,MM00-59

Done_time

10

Octet String

YYMMDDHHMM

Dest_terminal_Id

21

Octet String

目的終端MSISDN號碼(SP發(fā)送CMPP_SUBMIT消息的目標終端)

SMSC_sequence

4

Unsigned Integer

取自SMSC發(fā)送狀態(tài)報告的消息體中的消息標識。

關(guān)于State字段,如下解釋:

消息狀態(tài)名

最終狀態(tài)

描述

DELIVERED

DELIVRD

消息到達目標

EXPIRED

EXPIRED

消息過期

DELETED

DELETED

消息被刪除

UNDELIVERABLE

UNDELIV

消息未被送達

ACCEPTED

ACCEPTD

消息被認可

UNKNOWN

UNKNOWN

未知狀態(tài)

REJECTED

REJECTD

消息被彈回

其他消息結(jié)構(gòu),具體說明見中移動的CMPP協(xié)議。

 

4.         安全驗證

CMPP協(xié)議在CMPP_CONNECT中傳遞驗證消息。驗證消息為9字節(jié)的0+移動給出的密碼+當前時間戳字節(jié)數(shù)組的MD5算法后的字節(jié)。時間戳為 月日時分秒,10位。代碼算法如下:

private byte[] getMd5Code()

{

       byte[] buf=new byte[6+9+_Password.Length+10] ;   

       byte[] s_a=Encoding.ASCII.GetBytes(_SystemID); //就是企業(yè)代碼

       byte[] s_0={0,0,0,0,0,0,0,0,0};     //9字節(jié)的0,此處當作右補0

       byte[] s_p=Encoding.ASCII.GetBytes(_Password); //密碼

       this._timestamp =getTimestamp();    //取得認證碼時賦值字符串

       byte[] s_t=Encoding.ASCII.GetBytes(_timestamp); //10位字符串字節(jié)數(shù)組

       s_a.CopyTo(buf,0);   

       s_0.CopyTo(buf,6);  

       s_p.CopyTo(buf,6+9);  

       s_t.CopyTo(buf,6+9+_Password.Length);

       MD5 md5= new MD5CryptoServiceProvider(); //創(chuàng)建MD5類別

       return(md5.ComputeHash(buf,0,buf.Length));

}   

其中getTimestamp函數(shù)為返回例如“0710125959”(710125959秒)這樣的字符串,詳細代碼略過,有興趣請查看本文的附件代碼。

 

5.         廠商API問題

筆者公司所處廣東,廣東移動提供了華為的以C 形式的APISMEIDLL.dll),來幫助大家初期熟悉CMPP協(xié)議。但是,經(jīng)過開發(fā)測試,發(fā)現(xiàn)華為的API至少存在幾個問題:

1、  封裝成幾個API函數(shù),但是由于CMPP自身的復雜性,導致這些函數(shù)丑陋無比,參數(shù)多,而且難以明晰含義。華為的API,內(nèi)部將CMPP的驗證、事務(wù)階段分成幾個函數(shù)實現(xiàn),其中將發(fā)送SMSISMG功能以函數(shù)提供,竟然出現(xiàn)SubmitAExExEx之類的函數(shù)說明。

2、  CMPP的交互是異步的,需要多線程實現(xiàn)一邊發(fā)送,一邊接收反饋信息。此API應當是內(nèi)部維護一個線程進行CMPP_SUBMIT消息發(fā)送,但是華為API卻通過空循環(huán)之類的操作等待ISMG返回CMPP_SUBMIT_RESP得到相應的MSGID再返回(從而實現(xiàn)消息同步返回)。經(jīng)過測試,大約需要200毫秒,這個在實際SP的高性能需求場合根本無法滿足系統(tǒng)要求。

3、  接收短信必須依靠程序主動先發(fā)出函數(shù)HasDeliverMessage調(diào)用 ,得到有消息才可通過GetDeliverSMEx函數(shù)獲取消息,顯然,這種方式是低效率的,而且容易產(chǎn)生消息數(shù)據(jù)包丟失,表現(xiàn)為有些MO消息,SP接收不到。而且,令人疑惑的是,你還不能夠新開一個線程專門來做判斷并接收MO的動作,實際開發(fā)中一旦采用線程來做就回發(fā)生內(nèi)存保護錯誤(大概屬于同API自身的線程有沖突)。

4、  返回錯誤碼,往往又是華為自己定的一套錯誤碼(大概華為設(shè)計此API為了適應SMGP CMPP等多個協(xié)議),而且經(jīng)常變動,很是傷腦筋。

基于以上理由,我認為自己按照CMPP協(xié)議開發(fā)一個SP端程序,比較能夠滿足一般SP的需求。

 

四、C#實現(xiàn)

1、CMPP協(xié)議實現(xiàn)類CMPPClient

通過研究,筆者用C#寫了一組類實現(xiàn)自己的CMPP SP端程序(CMPPClient)。為了實現(xiàn)相關(guān)類,還需要編寫一些輔助類,并且首先要解決CMPP協(xié)議的數(shù)據(jù)結(jié)構(gòu)同C#的數(shù)據(jù)之間的轉(zhuǎn)換問題。

CMPPOctet String 實際上相當于C#中的byte[],所有CMPP消息的Octet String字段出了CMPP_SUBMITCMPP_DELIVERmsg_content字段外,其他的都可以認為是ASCII編碼,所以全部可以采用System.Text.Encoding.ASCII進行編碼和解碼;對于Msg_Content字段,由于一般情況下存在漢字信息傳輸.,所以默認的編/解碼應該為Encoding.Default,實際是什么編碼還要考察MSG_Fmt字段指示正文到底是什么編碼。

對于Unsigned Integer Interger字段,需要按照網(wǎng)絡(luò)字節(jié)順序和x86機器的字節(jié)編碼順序?qū)φ贞P(guān)系進行轉(zhuǎn)換,具體我設(shè)計了一個工具類提一些轉(zhuǎn)換方法使用:

public class BIConvert  //字節(jié) 整形 轉(zhuǎn)換類 網(wǎng)絡(luò)格式轉(zhuǎn)換為內(nèi)存格式

       {

              public static byte[] Int2Bytes(uint i)  //轉(zhuǎn)換整形數(shù)據(jù)的網(wǎng)絡(luò)次序字節(jié)數(shù)組

              {

                     byte[] t=BitConverter.GetBytes(i) ;

                     byte b=t[0];

                     t[0]=t[3];

                     t[3]=b;

                     b=t[1];

                     t[1]=t[2];

                     t[2]=b;

                     return(t);

              }

 

              public static uint Bytes2UInt(byte[] bs,int startIndex) //返回字節(jié)數(shù)組代表的整數(shù)數(shù)字,4個字節(jié)長度的數(shù)組

              {

                     byte[] t=new byte[4];

                     for(int i=0;i<4 && i< bs.Length-startIndex ;i++)

                     {

                            t[i]=bs[startIndex+i];

                     } 

                     byte b=t[0];

                     t[0]=t[3];

                     t[3]=b;

                     b=t[1];

                     t[1]=t[2];

                     t[2]=b;

                     return(BitConverter.ToUInt32(t,0));

              }

 

              public static uint Bytes2UInt(byte[] bs)  //沒有指定起始索引

              {

                     return( Bytes2UInt(bs,0));

              }

       }

 

其次,為了實現(xiàn)收發(fā)數(shù)據(jù)的“全雙工”,需要設(shè)計至少兩個線程處理socket的讀取和數(shù)據(jù)包寫入。另外,為了自動實現(xiàn)對數(shù)據(jù)鏈路的保持,以及自動實現(xiàn)數(shù)據(jù)包重發(fā)機值,我還增加了一個值守線程,自動處理以上問題。詳細見后代碼。另外,消息中有很多同時間有關(guān)的字段,但是這些時間相關(guān)字段并非按照統(tǒng)一規(guī)格編碼的,這個需要仔細研究協(xié)議或者實現(xiàn)代碼。

其三,為了解析/編碼數(shù)據(jù)包方便,我將SP端涉及到的消息以類的形式實現(xiàn),根據(jù)具體的消息類型,將數(shù)據(jù)包字節(jié)解析還原為特定的消息;另一方面,當需要發(fā)送一些消息時,將消息的各個字段,根據(jù)類型和編碼類型“組裝”成字節(jié)數(shù)組,以便Socket能夠發(fā)送出去。

其四,為了達到及時處理短消息的收發(fā),我大量采用了C#事件觸發(fā)來達到消息通知目的,而且,也設(shè)計一組事件參數(shù),供事件的具體監(jiān)聽者可以掌握需要的信息。

其五,需要注意多線程間的同步問題。

其六,填寫CMPP_SUBMIT消息需要注意內(nèi)容編碼、計費字段正確填寫

 

2、事件模型

大體上實現(xiàn)了十多個事件,這些事件具體為:

CMPP_DELIVER消息送來的是短消息送達報告時,發(fā)生消息送達報告事件:

public delegate void ReportEventHandler(object sender, ReportEventArgs e); 
      
CMPP_DELIVER消息送來的是用戶手機MO短消息時,發(fā)生短信到達事件,其他程序可以在處理此事件獲得消息的正文、手機號碼、SP服務(wù)號碼等信息:

public delegate void SMSEventHandler(object sender, SMSEventArgs e);  
      
ISMG發(fā)出CMPP_TERMINATE消息時,發(fā)生,具體的回應,我在具體實現(xiàn)中先自動進行了回復,產(chǎn)生此事件僅僅向外部程序(此事件的截取者)表達收到此消息,需要進行“善后清場”操作:

       public delegate void TerminateEventHandler(object sender,TerminateEventArgs e);  
             
SP主動終止連接時,發(fā)出CMPP_TERMINATE消息,ISMG會響應CMPP_TERMINATE_RESP消息,此事件表示收到此回應

       public delegate void TerminateRespEventHandler(object sender,TerminateRespEventArgs e); 

       以下兩個事件針對鏈路保持消息CMPP_ACTIVE_TESTCMPP_ACTIVE_TEST_RESP發(fā)生:

       public delegate void TestEventHandler(object sender,TestEventArgs e);

       public delegate void TestRespEventHandler(object sender,TestRespEventArgs e);
       SP
發(fā)出CMPP_CONNECT消息后,ISMG驗證,然后發(fā)出CMPP_CONNECT_RESP消息,此時激活此事件:

       public delegate void ConnectRespEventHandler(object sender,ConnectRespEventArgs e);

       SP取消某條端消息,發(fā)出CMPP_CANCEL后,ISMG響應此消息返回CMPP_CANCEL_RESP消息時,激活事件:

       public delegate void CancelRespEventHandler(object sender,CancelRespEventArgs e);
       SP
提交短信后,ISMG返回一個CMPP_SUBMIT_RESP 消息,包含“收條”(MSG_ID)在內(nèi),觸發(fā)此事件:

       public delegate void SubmitRespEventHandler(object sender,SubmitRespEventArgs e);

       查詢ISMG返回消息后,發(fā)生:

       public delegate void QueryRespEventHandler(object sender,QueryRespEventArgs e);
      
SP驗證通過后,作為應用邏輯需要得到通知,我特此加了此事件:

       public delegate void LogonSuccEventHandler(object sender,EventArgs e); //當成功登錄系統(tǒng)

       以下事件,不是基于CMPP消息,而是根據(jù)SPISMG消息隊列掃描后判斷觸發(fā)事件:

       public delegate void SocketClosedEventHandler(object sender,EventArgs e); //當套接字被檢測到關(guān)閉

       public delegate void FailedItemDeletedEventHandler(object sender,WaitingQueueItemEventArgs e); //當一條存在于等待隊列的消息超過60秒沒有回應

以上這些事件缺省實現(xiàn)保證了SPCMPP客戶對于ISMG的響應自動化,提供觸發(fā)事件保證調(diào)用此客戶端類的系統(tǒng)可以通過事件發(fā)生準確的控制SP端的內(nèi)部狀態(tài),獲取交互信息。

另一方面,由于這些大多數(shù)事件發(fā)生于數(shù)據(jù)包達到后的處理,實際上需要處理事件程序一定要“迅速”解決,或者干脆將消息轉(zhuǎn)換為可以暫存的消息形式,由其他程序進一步處理。CMPPSP端要滿足大量短信息應用需求,就必須嚴格控制消息交互處理邏輯不要太復雜,特別不要設(shè)計大量I/O處理;如果實在要處理,最好采用異步線程的方式來處理。

 

3、為了提高效率,開了3個線程:

       RecvISMGMsgThread   用于處理接收ISMG發(fā)送過來的消息,并根據(jù)消息、消息解析后的字段內(nèi)容觸發(fā)相應的事件。

       SendSPMsgThread        用于處理向ISMG發(fā)送數(shù)據(jù)包。注意,有些消息(譬如CMPP_ACTIVE_TEST)是系統(tǒng)自己產(chǎn)生的。另外,有些消息是收到ISMG的消息后需要立即回應給ISMG的,那么這些消息,全部進入內(nèi)部維護的消息隊列(_outSeqQueue)。該隊列會自動排序消息,所有需要發(fā)送的消息,進入此隊列,本線程不斷從隊列取出需要發(fā)送的消息,轉(zhuǎn)換成數(shù)據(jù)包,通過Socket發(fā)送到ISMG.

       DeamonThread      用于監(jiān)測數(shù)據(jù)連接socket是否可用,是否需要發(fā)出維持數(shù)據(jù)連接的測試數(shù)據(jù)包;有些消息發(fā)送過去了,過了協(xié)議規(guī)定的時間仍然沒有收到RESP消息,那么需要將消息從已經(jīng)發(fā)送的隊列中提取,重新加入到發(fā)送隊列中,排隊后等待送出。

       可以仔細分析提供的代碼,研究其中的具體實現(xiàn)。

 

五、問題小結(jié)

根據(jù)自己的經(jīng)驗,覺得以下幾點對于整個系統(tǒng)開發(fā)較為重要:

1、一定要正確理解協(xié)議。

很多網(wǎng)友交流時候,總抱怨協(xié)議濫,搞不定,其實很多原因?qū)儆谧约簺]有清楚理解協(xié)議。從我的接觸的移動ISMG來看,應該說實現(xiàn)協(xié)議還是很嚴格遵守CMPP的描述。倒是,一些網(wǎng)友自己開發(fā)的模擬器不是很規(guī)范(不是批評,鄭重聲明),需要自己在開發(fā)時候引起注意。

2、多線程互斥問題。

多個線程之間涉及一些隊列的操作,需要進行同步鎖定,否則容易引起問題。出現(xiàn)異常也需要及時捕獲,并紀錄作為錯誤信息參考,便于排除bug。

3、自己控制數(shù)據(jù)包流向和處理時間。

由于設(shè)計目標是高性能,所以在處理socket數(shù)據(jù)讀寫時候要注意對于一些事件處理不要過多消耗系統(tǒng)資源,避免引起數(shù)據(jù)包來不及處理而導致數(shù)據(jù)丟失。特別在數(shù)據(jù)繁忙時刻往往會使ISMG的吞吐性能下降,需要考慮對這種情況下的流量控制。有時,你不能夠指望ISMG如你所愿及時回應你,更為常見的是ISMG根本不返回RESP類型的數(shù)據(jù)包。另外,本協(xié)議處理數(shù)據(jù)收發(fā)采用阻塞Socket,有網(wǎng)友建議我采用異步非阻塞Socket,我想可能異步非阻塞Socket會更好。

4、服務(wù)監(jiān)控問題。

由于一些意外,往往會導致數(shù)據(jù)連接被中斷,這是,需要建立超時重建連接的機制。我給出的例子并未很好解決,希望其他方家指正。

5、字節(jié)順序問題。

這個問題,對于初接觸socket編程的人士往往造成很大麻煩。不過,CMPP協(xié)議設(shè)計的基本數(shù)據(jù)類型很簡單,僅需要按照本例子參考即可解決。

6、具體協(xié)議應用問題。

本例僅僅是一個按照協(xié)議要求實現(xiàn)CMPP協(xié)議的類,完整的SP端方案需要結(jié)合自己公司的實際要求,改造或者重用本例。限于篇幅,文中僅僅能夠列出重點片斷,詳細細節(jié)清參考供下載的代碼(附注釋)。本文僅僅是針對CMPP2.0協(xié)議進行討論開發(fā),協(xié)議的詳情請從移動夢網(wǎng)(http://www.monternet.com/moneditor/cs/SP/cmcc/)下載。其他技術(shù)參考可以到如下處獲取,也可察看網(wǎng)友的貼字獲取進一步詳細說明:

       天堂鳥交流論壇(http://www.spzone.net/bbs/index.asp

       CSDN社區(qū) 移動平臺
http://community.csdn.net/expert/forum.asp?url=/Expert/ForumsList.asp?roomid=63&typenum=1&whichpage=1

       SP論壇(http://www.spforum.net/jishu/Index.asp

如果你發(fā)現(xiàn)本人的實例存在問題(我想那簡直是一定的了),請不吝賜教myjobsdk@yahoo.com.cn

 

 后記:現(xiàn)在CMPP3。0也就是移動的MISC平臺版本的需要訂購關(guān)系確定才可以計費。不過不是本文討論的重點。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
企業(yè)短信應用平臺的設(shè)計
基于CMPP3.0的企業(yè)短信網(wǎng)關(guān)API設(shè)計
SP服務(wù)商Java短信平臺的軟件模型和實現(xiàn)
短信網(wǎng)關(guān)
C與java通訊小結(jié)
短信服務(wù)-API協(xié)議
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服