其实SDP是一个很简单的协议.关键在于搞清楚其中的概念.说实话,这里面的概念的确是很容易乱.
服务: 是一个实体,是一个服务类的一个实体.用来提供信息,执行某个动作.它可以由软件,硬件或两者的结合来组成.服务句柄属性是表示它的关键属性.
服务记录:保存了描述一个服务的信息.服务记录是由一个服务属性列表组成的.
服务类: 每一个服务都是服务类的一个实例。服务类定义提供对所有包含于服务记录中属性的定义。它也是用UUID来表示的.
服务属性:描述了某一个服务的一个特征。由两部分组成属性ID(16 bit)和属性值.
属性ID: 16位,也就是两个字节.服务所属的服务类决定了该服务的服务记录中的属性ID的语义.
属性值: 是一个数据元.
服务浏览组:由服务记录中的BrowseGroupList属性来表现.这个属性的值是一个UUID列表.其中保存的是浏览组的UUID.如果一个服务属于某个浏组,则它的BrowseGroupList属性中就有这个浏览组的UUID.
GroupID定义了一个浏览组.它也是一个属性值.
以上是SDP的核心概念.可以类比为每个服务记录是一个服务的定义.但服务类不需要服务记录来实际的定义.它们都是在属性中直接使用.因为这些服务类是SIG(The Bluetooth Special Interest Group (SIG))已经定义的.它们的UUID可参见Assigned Numbers.但用户自定义的服务浏览组是需要服务记录来定义的.
以下两个属性是每一个记录都必须有的
ServiceRecordHandle: 32位。SDP服务的服务记录的该属性为0x0000 0000.
ServiceClassIDList: 该属性决定了服务记录所表示的服务所属的服务类.
当某个服务的服务记录的ServiceClassIDList属性中包含了ServiceDiscoveryServerServiceClassID,则该服务记录就是一个SDP服务的定义。它的服务句柄是固定的0x00000000.
当某个服务的服务记录的ServiceClassIDList属性中包含了BrowseGroupDescriptorServiceClassID,则该服务记录就是一个浏览组的定义。这个服务记录中要用GroupID属性,定义该服务浏览组的UUID.
当某个服务的服务记录的ServiceClassIDList属性中包含了PublicBrowseRoot,则该服务属于公共浏览根目录.
ServiceDiscoveryServerServiceClassID = 0x1000
BrowseGroupDescriptorServiceClassID = 0x1001
PublicBrowseRoot = 0x1002 (注:在www.bluetooth.org新的Assigned Numbers文件中,PublicBrowseRoot已经改为PublicBrowseGroup)
#include <btsdp.h> //sdpdatabase.lib
static const TInt KSerialClassID = 0x1101;
static const TInt KChannel = 1; // Channel
static const TInt KUidBTAdvertiserAppValue = { 0xEFF55B8B };
_LIT( KServiceName, "Serial" );
_LIT( KServiceDescription, "Serial transfer" );
private: // Data
RSdp iSdpSession;
RSdpDatabase iSdpDatabase;
TSdpServRecordHandle iRecord;
void CbtAppView::StartAdvertiserL()
{
if (!iIsConnected)
{
User::LeaveIfError(iSdpSession.Connect());
// if (iSdpSession.Connect() != KErrNone)
// Panic( EBTAdvertiserFailedToOpenSession );
if (iSdpDatabase.Open(iSdpSession) != KErrNone)
Panic( EBTAdvertiserFailedToOpenDatabase );
iIsConnected =ETrue;
}
iSdpDatabase.CreateServiceRecordL(KSerialClassID, iRecord);
CSdpAttrValueDES* protocolDescriptorList =
CSdpAttrValueDES::NewDESL( NULL );
CleanupStack::PushL( protocolDescriptorList );
protocolDescriptorList
->StartListL() // List of protocols required for this method
->BuildDESL()
->StartListL()
->BuildUUIDL( KL2CAP )
->EndListL()
->BuildDESL()
->StartListL()
->BuildUUIDL( KRFCOMM )
->BuildUintL( TBuf8<1>( KChannel ) )
->EndListL()
->EndListL();
iSdpDatabase.UpdateAttributeL(
iRecord, KSdpAttrIdProtocolDescriptorList, *protocolDescriptorList );
CleanupStack::PopAndDestroy( protocolDescriptorList );
// Add a Unique ID to the record
iSdpDatabase.UpdateAttributeL( iRecord,
KSdpAttrIdServiceID,
KUidBTAdvertiserAppValue );
// Add a name to the record
iSdpDatabase.UpdateAttributeL( iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceName,
KServiceName );
// Add a description to the record
iSdpDatabase.UpdateAttributeL( iRecord,
KSdpAttrIdBasePrimaryLanguage +
KSdpAttrIdOffsetServiceDescription,
KServiceDescription );
}
CbtAppView::~CbtAppView()
{
if ( IsAdvertising() )
{
StopAdvertiser();
}
iSdpDatabase.Close();
iSdpSession.Close();
}