其實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();
}