忙著應(yīng)付保密檢查和其他一些事情,把Xmail的事情耽擱了。晚上的時(shí)間我看了一下關(guān)于短信技術(shù)的應(yīng)用。根據(jù)一些文章和自己的感悟簡(jiǎn)單談?wù)劇?/p> 中國(guó)電信和中國(guó)移動(dòng)的短信協(xié)議要求客戶端主動(dòng)連接到網(wǎng)關(guān)收取信息,并且接受的連接只能有一個(gè)。 因此客戶端的接收程序必須盡快處理收到的信息,好盡快接收下一個(gè)信息。而客戶端的程序又有很多事情必須處理,比如寫日志并分發(fā)給相關(guān)的應(yīng)用。 開始我用多線程的方式,即接收程序收到從網(wǎng)關(guān)發(fā)來的信息后,啟動(dòng)一個(gè)新線程處理收到的信息,本身接著收下一個(gè)信息。新啟動(dòng)的線程負(fù)責(zé)寫日志,然后分發(fā)給相關(guān)的應(yīng)用。這種方式運(yùn)行起來效果不錯(cuò)。 接著又遇到一個(gè)問題,寫日志和分發(fā)給應(yīng)用的程序是兩個(gè)不相關(guān)的東西,放在一起有點(diǎn)別扭。寫日志的程序?qū)?shí)時(shí)性要求不高,只要保證記錄了就可以;而分發(fā)程序需要盡量快,不應(yīng)該等日志完了再執(zhí)行。再起一個(gè)線程寫日志,一個(gè)線程分發(fā)? 這樣線程多了反而更慢,不太好。 對(duì)與從網(wǎng)關(guān)收到的信息我們可能有許多處理程序,比如一個(gè)是寫日志,一個(gè)是分發(fā)給應(yīng)用。就日志來說,就有寫數(shù)據(jù)庫(kù)、寫文本文件、控制臺(tái)輸出等。所以我采用了消息隊(duì)列的方式,這樣接收程序收到從網(wǎng)關(guān)來的信息后送出一個(gè)消息到消息隊(duì)列中,需要處理的程序自己來取就是了。這個(gè)消息隊(duì)列用的是 Topic/Subscribe模式,就是接收程序發(fā)出的同一個(gè)消息可能被多個(gè)處理程序接受。這樣對(duì)信息的不同處理,我就可以寫不同的消息處理程序。 接收完了,看看向網(wǎng)關(guān)發(fā)送信息的情況。短信網(wǎng)關(guān)一般也只允許一個(gè)連接進(jìn)行發(fā)送,而且中國(guó)電信和中國(guó)移動(dòng)使用的短信網(wǎng)關(guān)協(xié)議都是異步的,這樣用消息隊(duì)列的發(fā)送也很理想。 整體框架如下面這幅圖 : Transport Service 是和網(wǎng)關(guān)通訊的程序。它負(fù)責(zé)保持連接、發(fā)送信息給網(wǎng)關(guān)、接收網(wǎng)關(guān)來的信息,并把信息發(fā)送到消息隊(duì)列 Deliver Controller 是分發(fā)信息給相關(guān)應(yīng)用的控制器。它從消息隊(duì)列中收取Deliver信息,然后根據(jù)信息的內(nèi)容或者用戶的狀態(tài),用不同的Application Deliver把信息分發(fā)給應(yīng)用 Application Deliver 負(fù)責(zé)具體分發(fā)信息給應(yīng)用。不同的應(yīng)用可能要求不同的信息接受方式,比如多數(shù)是用HTTP方式,分發(fā)程序用POST方法把信息提交給應(yīng)用,這中方式用的是 AppDeliverHttpPost;有的是用SOAP,用的就是AppDeliverSoap了??傊裁葱路椒?,寫一個(gè)Application Deliver就可以了。 Logger 就是寫日志的程序。它從消息隊(duì)列中收取所以消息,然后寫日志。如果要有不同的日志方法可以寫不同的Logger,比如我有一個(gè)DBLogger,是向數(shù)據(jù)庫(kù)里寫日志的實(shí)現(xiàn)。 Sender 是通過Transport Service發(fā)送Submit信息給網(wǎng)關(guān)的程序。短信協(xié)議是異步的,但多數(shù)應(yīng)該要求同步,就是要知道發(fā)送是否成功。因此Sender多提供了一個(gè)實(shí)現(xiàn)同步的方法。Sender發(fā)送后,從消息隊(duì)列中等待發(fā)送的結(jié)果,然后返回結(jié)果。 Web Service 是接受應(yīng)用發(fā)送信息的接口。為什么要這個(gè)呢?和接收一樣,多數(shù)應(yīng)用發(fā)送信息的時(shí)候是用HTTP的POST方法。而且這樣應(yīng)該不應(yīng)該知道短信協(xié)議的數(shù)據(jù)包格式,這樣同一個(gè)應(yīng)該可以給不同的短信協(xié)議使用,比如中國(guó)電信的SMGP和中國(guó)移動(dòng)的CMPP。 Application 就是最終處理短信的應(yīng)用了。它和短信協(xié)議無關(guān)。 在實(shí)際實(shí)現(xiàn)中,我使用了J2EE。我本來對(duì)J2EE挺煩的,不過這次效果不錯(cuò),特別是它的JMS,正好適合我的需要。開始我自己做消息隊(duì)列管理,后來發(fā)現(xiàn)做Topic方式的實(shí)現(xiàn)比較麻煩,所以還是用現(xiàn)成的吧。Application Server選用了JBoss,當(dāng)然也可以選用JRun,這兩個(gè)用JMX,比較容易寫自己的MBean放到作為應(yīng)用服務(wù)的Service。 其中Transport Service就是一個(gè)JMX的MBean。另外根據(jù)JRun和JBoss的要求,做了一下擴(kuò)展,很順利的作為應(yīng)用服務(wù)器中的一個(gè)服務(wù)執(zhí)行了。為什么用 JMX?因?yàn)樗容^容易管理,比如我要修改Transport Service的連接超時(shí)參數(shù),用HttpAgentAdapter直接修改就可以了,服務(wù)本身就不用重新啟動(dòng)。 Deliver Controller、Logger我都做成了MessageBean,好接收消息隊(duì)列。Sender和Application Deliver是Stateless的SessionBean,方便別人調(diào)用。 用了EJB還一個(gè)好處是,我Deploy和Undeploy其中的某些Bean的時(shí)候,不影響到其他Bean提供服務(wù)。比如新做了一個(gè) Application Deliver,直接Deploy后,這個(gè)功能就可以用了。其他服務(wù)都不需要重新啟動(dòng),有點(diǎn)Plug&Play的味道。 另外,數(shù)據(jù)庫(kù)我用的是MySQL。 |
|