(1)基础知识补充--关于cmnet和cmwap
众所周知,中国移动对gprs分组数据业务进行了人为的限制,把它分成了
“cmnet” 和“cmwap”两种接入方式。对于cmnet来说,是允许手机直接接入internet
互联网,允许tcp长连接,允许udp数据包,可以说 cmnet是gprs服务本来的面貌;
而cmwap则是被“阉割”版的gprs服务,所有的数据只能先通过一个叫做wap网关的
服务器中 转才能发送到公网上去,而且不能够支持tcp长连接(这个长连接的意思是,
连上了以后,就不断开。)不支持udp数据包,只允许http连接请求 通过。我们可以
简单地把cmwap理解为只能够用http协议进行通信的gprs方式,cmnet则是没有这种限制
可以随意连接手机到互 联网的gprs方式。“cmnet”连接虽好,但是是3分钱1k的流量,
一首3M的mp3,如果采用cmnet联网方式下载的话 3*1024*3/100=92.16元,一首歌
竟然要这么多钱才能下载下来;如果采用cmwap联网方式的话,多数是有流量包月服务
的, 可以等效为开销很小。这也就很容易就可以解释,为什么现在的手机软件绝大
多数都是采用cmwap连接的了。
(2)关于自动选择接入点
相信各位在做symbian 2nd开发的时候,不可避免的会遇到连接gprs的情况。
在默认的情况 下,symbian会弹出一个接入点选择对话框,例如“gprs连接互联网”、
“移动梦网”,“Nokia.com”之类的选择。由于上面所述的 cmwap和cmnet在收费方面的
区别,在软件中一旦用户选错了接入点,那么或许会面临巨额的流量费。这是用户与
软件作者都不愿看到的 情况。所以自然而然,就会提出这个要求,如何屏蔽掉这个接入
点选择呢?或者更确切的说,让软件代替用户选择合适的接入点,既可以减少用户
误 操作的机率,又可以简化程序对错误异常处理的工作量。
说是自动选择接入点其实,只是根据接入点的名称来代替用户做选择,如果要选择
cmwap的话。
这里给出一个解决的方法(直接把头定义可能有没用的文件考过来了,
具体各个头文件关联的lib,google一下就都有了,添加到mmp文 件中即可):
#include <avkon.hrh>
#include <aknnotewrappers.h>
#include <commdb.h>
#include <commdbconnpref.h>
#include <cdbcols.h>
#include <cdbstore.h>
#include <AgentClient.h>
#include <apselect.h>
#include <uri8.h>
#include <http.h>
#include <chttpformencoder.h>
#include <HttpStringConstants.h>
#include <http/RHTTPTransaction.h>
#include <http/RHTTPSession.h>
#include <http/RHTTPHeaders.h>
#include <ExampleClient.rsg>
#include "HttpCltEngine.h"
这里是连接的函数,选择cmwap做为接入点的方法
TBool CClientEngine::ConnectSmoothly()
{
if(iCurConn == EConnected) return ETrue ;
// 利用iSocketServ打开一个connection
User::LeaveIfError(iConn.Open(iSocketServ)) ;
// 这里就是对CCommsDatabase这个数据库类,声明一个CommonDB的对象
CCommsDatabase* const comDB = CCommsDatabase::NewL(EDatabaseTypeIAP);
CleanupStack::PushL(comDB);
// 这个table view是用来遍历已有的接入点列表用的
CCommsDbTableView *myIapTableView = comDB->OpenTableLC(TPtrC(IAP));
TBuf<100> buf ;
TBuf<5> txt ;
TUint16 chr_meng = 0x68A6 ; // '梦'的内码
TUint16 chr_wang = 0x7F51 ; // '网'的内码
TUint32 iapId = 1024 ; // 这个初始化为一个非法的接入点id
TUint32 iApPos = 0 ;
TInt i ;
// 首先移动到第一条接入点记录,如果没有就创建一个
// 这一步比较狠,哪怕把所有的接入点都删掉,仍然可以创建一个新的接入点
// 继续联网,关于创建接入点的代码详见下文
if(myIapTableView->GotoFirstRecord() != KErrNone) {
iapId = CreateWapAp() ;
} else {
do {
buf.Zero();
// 这里是读取接入点的名称
myIapTableView->ReadTextL(TPtrC(COMMDB_NAME), buf);
// 将名称全部改为大写,对于N72,N70的水货,都是小写的
// "cmwap"和"cmnet",都改为大写容易识别
buf.UpperCase() ;
// 首先查找这个接入点名称里面是否含有"梦网"二字,
// 如果有,自然就是“移动梦网”这个接入点了,这个接入点
// 是中移动强制放到手机里面去的,所有的“行货”手机应该都有的
// 这个接入点就是cmwap的,所以这个如果找到,就代表成功得到了
// 支持cmwap的接入点,可以获取id进行连接了。
iApPos = (TUint32)(KErrNotFound) ;
for(i = 0 ; i < buf.Length() ; i++) {
if((TUint16)(buf[i]) == chr_meng) {
if(((i+1) < buf.Length()) && ((TUint16)(buf[i+1]) == chr_wang)) {
iApPos = 1 ;
break ;
}
}
}
// 这里就是找到了含有“梦网”二字的接入点,可以跳出循环了
if(iApPos != KErrNotFound) {
myIapTableView->ReadUintL(TPtrC(COMMDB_ID), iapId) ;
break ;
}
// 检查名称中是否含有“NOKIA”,同理,“nokia.com”也是
// cmwap的接入点,如果含有则跳出
iApPos = buf.Find(_L("NOKIA")) ; // Nokia.com AP in other phones ?
if(iApPos != KErrNotFound) {
myIapTableView->ReadUintL(TPtrC(COMMDB_ID), iapId);
break ;
}
// 检查名称中是否含有WAP,这主要是针对水货手机直接标明
// "cmwap"或者"cmnet"或者"wap连接"之类的,总之,只要有"WAP"
// 字样,咱就认它是cmwap的接入点
iApPos = buf.Find(_L("WAP")) ; // any wap are all right
if(iApPos != KErrNotFound) {
myIapTableView->ReadUintL(TPtrC(COMMDB_ID), iapId) ;
break ;
}
} while (KErrNone == myIapTableView->GotoNextRecord()) ;
}
// 这里是清理common db的对象和table view的对象了
CleanupStack::PopAndDestroy(2, comDB); // for myIapTableView, db release
// 这里是一个双保险,如果手机中确实有接入点,但是上面的循环又没有找到
// 这里就是要创建一个新的支持cmwap的接入点了
if(iapId == 1024) iapId = CreateWapAp() ;
// 下面就是利用刚刚所选择的接入点id,来代替用户选择了
TCommDbConnPref connectPref;
// setup preferences
connectPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt) ;
connectPref.SetDirection(ECommDbConnectionDirectionOutgoing) ;
connectPref.SetBearerSet(ECommDbBearerGPRS) ;
// 这里的SetIapId就是代替用户把选好的接入点id传入了
connectPref.SetIapId(iapId) ;
// 接下来就是开始使用刚刚选择的接入点开始连接了
TInt errConnect = 0 ;
errConnect = iConn.Start(connectPref);
if(errConnect == KErrNone) {
RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
RStringPool pool = iSession.StringPool();
// Attach to socket server
connInfo.SetPropertyL(pool.StringF(HTTP::EHttpSocketServ,
RHTTPSession::GetTable()), THTTPHdrVal(iSocketServ.Handle()));
// Attach to connection
TInt connPtr = REINTERPRET_CAST(TInt, &iConn);
connInfo.SetPropertyL(pool.StringF(HTTP::EHttpSocketConnection,
RHTTPSession::GetTable()), THTTPHdrVal(connPtr));
// set current connection connected
iCurConn = EConnected ;
} else {
iCurConn = ENotConnected ;
return EFalse ;
}
return ETrue ;
}
(3)关于创建接入点的问题
直接代码上见功夫吧,把创建接入点的函数直接贴出来,当初可是很辛苦才调试出来的代码啊!!
// 这个是创建的接入点的数据库名称,你可以改成自己喜欢的
#define KIAPCOMMDBNAME _L("CMWAP GPRS")
TInt CClientEngine::CreateWapAp()
{
TCommDbOpeningMethod OpeningMethod;
TInt error;
TUint32 GPRSId;
// 还是打开common db这个数据库,与上次的只读不同,这次是准备写入了
CCommsDatabase* commsDb = CCommsDatabase::NewL(EDatabaseTypeIAP,OpeningMethod);
CleanupStack::PushL(commsDb);
// 打开common db数据库中的OUTGOING_GPRS表,这个表是存放gprs
// 对外连接方式数据的
CCommsDbTableView* commsView = commsDb->OpenTableLC(TPtrC(OUTGOING_GPRS));
//插入一条数据,id是GPRSId
TRAP(error,commsView->InsertRecord(GPRSId));
if (error!=KErrNone) return -1;
// 这里是写入这个接入点的设置,就跟在手机中设置接入点是一样的
// 但是需要加入好多BOOL值
commsView->WriteTextL(TPtrC(COMMDB_NAME),_L("WayneGPRS"));
commsView->WriteBoolL(TPtrC(GPRS_IF_PROMPT_FOR_AUTH), ETrue);
commsView->WriteBoolL(TPtrC(GPRS_IP_ADDR_FROM_SERVER), ETrue);
commsView->WriteBoolL(TPtrC(GPRS_IP_DNS_ADDR_FROM_SERVER), ETrue);
commsView->WriteTextL(TPtrC(GPRS_IP_GATEWAY), _L("0.0.0.0"));
commsView->WriteTextL(TPtrC(GPRS_IF_AUTH_NAME), _L(""));
commsView->WriteTextL(TPtrC(GPRS_IF_AUTH_PASS),_L(""));
commsView->WriteTextL(TPtrC(GPRS_APN), _L("cmwap"));
commsView->WriteUintL(TPtrC(GPRS_PDP_TYPE), 0);
commsView->WriteBoolL(TPtrC(GPRS_IF_PROMPT_FOR_AUTH), EFalse);
commsView->WriteTextL(TPtrC(GPRS_IF_NETWORKS), _L("ip"));
commsView->WriteBoolL(TPtrC(GPRS_HEADER_COMPRESSION), EFalse);
commsView->WriteBoolL(TPtrC(GPRS_DATA_COMPRESSION), EFalse);
commsView->WriteUintL(TPtrC(GPRS_REQ_PRECEDENCE), 0);
commsView->WriteUintL(TPtrC(GPRS_REQ_DELAY), 0);
commsView->WriteUintL(TPtrC(GPRS_REQ_RELIABILITY), 0);
commsView->WriteUintL(TPtrC(GPRS_REQ_PEAK_THROUGHPUT), 0);
commsView->WriteUintL(TPtrC(GPRS_REQ_MEAN_THROUGHPUT), 0);
commsView->WriteUintL(TPtrC(GPRS_MIN_PRECEDENCE), 0);
commsView->WriteUintL(TPtrC(GPRS_MIN_DELAY), 0);
commsView->WriteUintL(TPtrC(GPRS_MIN_RELIABILITY), 0);
commsView->WriteUintL(TPtrC(GPRS_MIN_PEAK_THROUGHPUT), 0);
commsView->WriteUintL(TPtrC(GPRS_MIN_MEAN_THROUGHPUT), 0);
commsView->WriteBoolL(TPtrC(GPRS_ANONYMOUS_ACCESS), EFalse);
commsView->WriteBoolL(TPtrC(GPRS_USE_EDGE), EFalse);
commsView->WriteBoolL(TPtrC(GPRS_ENABLE_LCP_EXTENSIONS), EFalse);
commsView->WriteBoolL(TPtrC(GPRS_DISABLE_PLAIN_TEXT_AUTH), EFalse);
commsView->WriteUintL(TPtrC(GPRS_AP_TYPE), 0);
commsView->WriteUintL(TPtrC(GPRS_QOS_WARNING_TIMEOUT), -1);
commsView->WriteUintL(TPtrC(GPRS_PDP_TYPE), 0);
commsView->WriteTextL(TPtrC(GPRS_PDP_ADDRESS), _L(""));
commsView->WriteTextL(TPtrC(GPRS_IF_PARAMS), _L(""));
commsView->WriteUintL(TPtrC(GPRS_IF_AUTH_RETRIES), 0);
commsView->WriteTextL(TPtrC(GPRS_IP_NETMASK), _L(""));
commsView->WriteTextL(TPtrC(GPRS_IP_ADDR),_L("0.0.0.0"));
commsView->WriteTextL(TPtrC(GPRS_IP_NAME_SERVER1),_L("0.0.0.0"));
commsView->WriteTextL(TPtrC(GPRS_IP_NAME_SERVER2),_L("0.0.0.0"));
// 告诉common db的view类数据已经变化了,使添加生效
// 在加入新的记录之前,必须调用这个PutRecordChanges函数
// 否则就前面那些设置就白忙活了。
TRAP(error,commsView->PutRecordChanges());
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(commsView);
// 在NETWORK表中添加记录
TUint32 networkId;
commsView = commsDb->OpenTableLC(TPtrC(NETWORK));
TRAP(error,commsView->InsertRecord(networkId));
if (error!=KErrNone) return -1;
// 设置数据内容
commsView->WriteTextL(TPtrC(COMMDB_NAME), _L("WayneNETWORK"));
// 保存设置,并使添加操作生效
TRAP(error,commsView->PutRecordChanges(EFalse, EFalse));
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(commsView);
// 查找手机的LOCATION ID
TInt result;
TUint32 locationId;
TUint32 mobileLocationId;
commsView = commsDb->OpenTableLC(TPtrC(LOCATION));
result = commsView->GotoFirstRecord();
TBuf<128> locationName;
while (result == KErrNone) {
commsView->ReadTextL(TPtrC(COMMDB_NAME), locationName);
commsView->ReadUintL(TPtrC(LOCATION_MOBILE), locationId);
if (locationName.Match(_L("Mobile"))!= KErrNotFound)
mobileLocationId = locationId;
result = commsView->GotoNextRecord();
}
CleanupStack::PopAndDestroy(commsView);
// 利用刚刚找到的LOCATION ID在IAP表中添加记录
TUint32 iapId;
commsView = commsDb->OpenTableLC(TPtrC(IAP));
TRAP(error,commsView->InsertRecord(iapId));
if (error!=KErrNone) return -1;
// 设置记录的内容
commsView->WriteTextL(TPtrC(COMMDB_NAME), KIAPCOMMDBNAME);
commsView->WriteTextL(TPtrC(IAP_SERVICE_TYPE), TPtrC(OUTGOING_GPRS));
commsView->WriteUintL(TPtrC(IAP_SERVICE), GPRSId);
commsView->WriteUintL(TPtrC(IAP_NETWORK_WEIGHTING), 0);
commsView->WriteUintL(TPtrC(IAP_NETWORK), networkId);
commsView->WriteUintL(TPtrC(IAP_BEARER), 2);
commsView->WriteTextL(TPtrC(IAP_BEARER_TYPE), TPtrC(MODEM_BEARER));
commsView->WriteUintL(TPtrC(IAP_LOCATION), mobileLocationId);
// 添加这条新的记录
TRAP(error,commsView->PutRecordChanges());
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(commsView);
// 在WAP_ACCESS_POINT表中添加记录
TUint32 wapId;
commsView = commsDb->OpenTableLC(TPtrC(WAP_ACCESS_POINT));
TRAP(error,commsView->InsertRecord(wapId));
if (error!=KErrNone) return -1;
commsView->WriteTextL(TPtrC(COMMDB_NAME), _L("CMWAP GPRS"));
commsView->WriteTextL(TPtrC(WAP_CURRENT_BEARER), TPtrC(WAP_IP_BEARER));
// 使添加操作生效
TRAP(error,commsView->PutRecordChanges());
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(commsView);
// 在WAP_IP_BEARER表中添加记录
TUint32 wapIPId;
commsView = commsDb->OpenTableLC(TPtrC(WAP_IP_BEARER));
TRAP(error,commsView->InsertRecord(wapIPId));
if (error!=KErrNone)
{
return -1;
}
// 属性记录设置
commsView->WriteUintL(TPtrC(WAP_ACCESS_POINT_ID), wapId);
commsView->WriteTextL(TPtrC(WAP_GATEWAY_ADDRESS), _L("0.0.0.0"));
commsView->WriteUintL(TPtrC(WAP_WSP_OPTION),EWapWspOptionConnectionOriented);
commsView->WriteBoolL(TPtrC(WAP_SECURITY), EFalse);
commsView->WriteUintL(TPtrC(WAP_IAP),iapId);
commsView->WriteUintL(TPtrC(WAP_PROXY_PORT), 0);
commsView->WriteTextL(TPtrC(WAP_PROXY_LOGIN_NAME), _L(""));
commsView->WriteTextL(TPtrC(WAP_PROXY_LOGIN_PASS), _L(""));
// 添加完成
TRAP(error,commsView->PutRecordChanges(EFalse, EFalse));
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(commsView);
// 在接入点菜单中添加新增的接入点项
CStoreableOverrideSettings* overrides = CStoreableOverrideSettings::NewL(CStoreableOverrideSettings::EParamListFull);
CleanupStack::PushL(overrides);
CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref pref;
pref.iRanking = 1;
pref.iDirection = ECommDbConnectionDirectionOutgoing;
pref.iDialogPref = ECommDbDialogPrefDoNotPrompt;
pref.iBearer.iBearerSet = ECommDbBearerGPRS;
pref.iBearer.iIapId=iapId;
TRAP(error,overrides->SetConnectionPreferenceOverride(pref));
if (error!=KErrNone) return -1;
CleanupStack::PopAndDestroy(overrides);
// 这里是添加cmwap的网关代理,著名的10.0.0.172
// 按照老外的原话是"proxy for chinese fuckers"
TUint32 proxiesId;
CCommsDbTableView* view7 = commsDb->OpenTableLC(TPtrC(PROXIES));
User::LeaveIfError( view7->InsertRecord(proxiesId));
view7->WriteUintL(TPtrC(PROXY_ISP), GPRSId);
view7->WriteTextL(TPtrC(PROXY_SERVICE_TYPE), TPtrC(OUTGOING_GPRS));
view7->WriteBoolL(TPtrC(PROXY_USE_PROXY_SERVER), ETrue);
view7->WriteLongTextL(TPtrC(PROXY_SERVER_NAME), _L("10.0.0.172"));
view7->WriteTextL(TPtrC(PROXY_PROTOCOL_NAME), _L("http"));
view7->WriteUintL(TPtrC(PROXY_PORT_NUMBER),80);
error = view7->PutRecordChanges(EFalse,EFalse);
if(error != KErrNone) User::Leave(error);
CleanupStack::PopAndDestroy(overrides);
CleanupStack::PopAndDestroy(commsDb);
return iapId;
}