明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

SMS中用Unicode編碼發(fā)送中文

[摘要]SMS是由Esti 所制定的一個(gè)規(guī)范(GSM 03.40 和 GSM 03.38)。有兩種方式來(lái)發(fā)送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文...

SMS是由Esti 所制定的一個(gè)規(guī)范(GSM 03.40 和 GSM 03.38)。有兩種方式來(lái)發(fā)送和接收SMS消息:文本模式或者PDU(protocol description unit)模式。文本模式只能發(fā)送普通的ASCII字符,而要發(fā)送圖片、鈴聲、其它編碼的字符(如中文)就必須采用PDU模式。

       PDU模式中,可以采用三種編碼方式來(lái)編碼要發(fā)送的內(nèi)容,分別是 7-bit編碼、8-bit編碼、16-bit編碼。7-bit編碼用于發(fā)送普通的ASCII字符;8-bit編碼通常用于發(fā)送數(shù)據(jù)消息,比如圖片和鈴聲等;而16-bit編碼用于發(fā)送Unicode字符。在這三種編碼方式下,可以發(fā)送的最大字符數(shù)分別是 160、 140、 70。

       若要發(fā)送中文(或日文等),必須采用PDU模式的Unicode編碼方式。

我最近參與了一個(gè)在linux下收發(fā)短信的項(xiàng)目。其中,需要實(shí)現(xiàn)中文的發(fā)送和接收。由于原來(lái)沒有中文編碼、Unicode編碼的經(jīng)驗(yàn),所以查了一些資料,也在一些論壇上提了一些問題,F(xiàn)在把它整理出來(lái),希望對(duì)以后再做類似項(xiàng)目的朋友有個(gè)幫助。我寫的比較簡(jiǎn)單,關(guān)于PDU的規(guī)范,可以看這里:http://www.ascend-tech.com.cn/sustain/SMS_PDU-mode.pdf ,或者去wavecom的網(wǎng)站上找找看。

 

1、 GB2312 編碼到Unicode 編碼的轉(zhuǎn)換

 

在 Redhat 7.3系統(tǒng)上,默認(rèn)是用GB2312編碼保存中文字符的(對(duì)于中英文混合的文本也是如此)。所以首先需要把 GB2312 編碼的字符串轉(zhuǎn)換到 Unicode編碼的字符串。GB2312編碼是一種多字節(jié)編碼方式,對(duì)于中文,用2個(gè)字節(jié)表示,對(duì)于英文,用1個(gè)字節(jié)表示,就是英文的ascii碼。(注:我沒有仔細(xì)看過(guò)GB2312編碼的規(guī)范,以上理解是實(shí)際開發(fā)中得出來(lái)的,不能保證正確性)。Unicode編碼是雙字節(jié)編碼方式,對(duì)所有字符,都采用2個(gè)字節(jié)編碼。在linux平臺(tái)上,GB2312編碼到Unicode編碼的轉(zhuǎn)換,可以有三種實(shí)現(xiàn)方式(或者更多):

1)、用 mbstowcs () 函數(shù)。就是多字節(jié)編碼到寬字符的轉(zhuǎn)換。我試過(guò)它,可以正確的轉(zhuǎn)換,但是這個(gè)函數(shù)可能不是很可靠。

 

2)、用 GB2312 à Unicode 的轉(zhuǎn)換表,手動(dòng)查表轉(zhuǎn)換。網(wǎng)上有這樣的轉(zhuǎn)換表,你需要對(duì)每一個(gè)GB2312字符,根據(jù)它是中文字符還是英文字符,分別轉(zhuǎn)換。

 

3)、用 iconv () 函數(shù)。這可能是linux上的標(biāo)準(zhǔn)的方法,不僅可以轉(zhuǎn)換GB2312到Unicode,還可以在任意的兩種編碼之間轉(zhuǎn)換(前提是linux系統(tǒng)要支持這些編碼)。

首先要用 iconv_open(), 打開一個(gè)轉(zhuǎn)換句柄,指定兩種轉(zhuǎn)換前的編碼和轉(zhuǎn)換后的編碼。

然后用 icnov() 作轉(zhuǎn)換。最后用 iconv_close()關(guān)閉句柄,釋放資源。

#include <iconv.h>

 

#define BUFLEN 200

char inbuf[BUFLEN];

char outbuf[BUFLEN];

char* pin = inbuf;

char* pout = outbuf;

 

…打開文件,讀入GB2312數(shù)據(jù)到inbuf,數(shù)據(jù)長(zhǎng)度為 len

 

int inleft = len;

int outleft = BUFLEN;

 

iconv_t cd;

if((cd = iconv_open(“gb2312”, “unicode”)) == (iconv_t)-1)

        return –1;

if(iconv(cd, &pin, &inleft, &pout, &outleft) == (size_t)-1)

        return –1;

iconv_close(cd);

使用 iconv () 時(shí),需要注意參數(shù)的使用,inleft 是輸入緩沖區(qū)數(shù)據(jù)數(shù)據(jù)長(zhǎng)度,outleft是輸出緩沖區(qū)大小。(需要保證輸出緩沖區(qū)足夠大)。

轉(zhuǎn)換以后,outleft 是outbuf中空閑空間的大小,所以 BUFLEN-outleft 才是真正的Unicode數(shù)據(jù)長(zhǎng)度。

注意:不論是GB2312編碼,還是Unicode編碼,在內(nèi)存中都是一些字節(jié)序列,所以我們可以統(tǒng)一用 類型為 char(或者unsigned char)的字符數(shù)組來(lái)保存。所以,BUFLEN-outleft 是 字符(char)個(gè)數(shù),而不是Unicode字符個(gè)數(shù)。

 

 

2、  Unicode 編碼到 16-bit 編碼的轉(zhuǎn)換

 

在得到 Unicode編碼以后,還需要轉(zhuǎn)換到 PDU 的16-bit 編碼,才可以正確的發(fā)送。在這個(gè)轉(zhuǎn)換過(guò)程中,需要注意兩點(diǎn):

1)、Unicode 編碼最開始的 0xFEFF標(biāo)志要被去除,在0xFEFF之后的內(nèi)容,才是真正的Unicode字符。(至于為什么有這個(gè)0xfeff標(biāo)志,知道的朋友告訴我一聲,呵呵)。

 

2)、Unicode 是雙字節(jié)字符,由于我的系統(tǒng)是小端字節(jié)序(little-endian),也就是說(shuō),在存儲(chǔ)的時(shí)候,是先低位,后高位,例如“中”的Unicode編碼是 0x4E2D,存儲(chǔ)的時(shí)候是 2D4E,在轉(zhuǎn)換到 16-bit編碼的時(shí)候,要注意這個(gè)順序的不同。當(dāng)然,如果你的系統(tǒng)是大端字節(jié)序(big-endian),那么就不用這樣做了。

 

3)、為了將0x4E2D 的Unicode編碼轉(zhuǎn)換到 “4E2D” 的16-bit編碼,可以用 sprintf(buf,  “%02X”,  outbuf[i]) 對(duì)每一個(gè)字節(jié)作轉(zhuǎn)換。

 

 

3、正確計(jì)算16-bit 編碼的消息體長(zhǎng)度

       PDU規(guī)范中,需要包括消息體的長(zhǎng)度,這里你要小心計(jì)算。

 

4、正確設(shè)置 First-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP

 

在PDU格式中,F(xiàn)irst-Octet 、TP-MR、TP-PID、TP-DCS、TP-VP的設(shè)置正確與否,對(duì)能否發(fā)送 Unicode 至關(guān)重要。根據(jù)協(xié)議規(guī)范以及我的調(diào)試結(jié)果,以上幾個(gè)標(biāo)志的正確設(shè)置分別為(都是16進(jìn)制):

First-Octet : 11    

TP-MR :      00

TP-PID :      00

TP-DCS :     08    (編碼方式,16-bit)

TP-VP :              A7          

 

       經(jīng)過(guò)以上步驟,已經(jīng)可以做到發(fā)送中文字符了。

希望這篇文檔,能為準(zhǔn)備在linux下做短信開發(fā)的朋友提供一些幫助。

       

 

參考資料:

★ An introduction to the SMS in PDU mode GSM Recommendation phase 2