放眼市场上各种各样的JSR82 MIDlets,有一点需要注意,一些MIDlets并没有以一种合适的方式处理服务发现协议(SDP)记录。在蓝牙领域内SDP记录是非常难以领会的,但是在JSR82中并没有这么困难。
这篇短小的文章会就SDP记录的一般问题给予一些建议。
我们先简要地看看为什么需要SDP记录。SDP记录是一种用来确认设备上的一种特定服务的记录。没有SDP记录,一部移动电话就不可能检测到另一个设备上的服务。大部分的电话拥有一个以上的SDP记录,例如,它们很可能有对于L2CAP和串口的记录。
关于SDP记录最主要的问题的就是很多开发者忘记了从数据库中删除SDP记录。这就导致了最终用户不能重新连接来运行游戏。
下面两张简单的图片说明了这个问题:
图1 SDP连接成功
如图1所示两个MIDlets正在试图进行连接,并且连接成功。
图2 SDP连接失败
在图2中我们可以看到,一个MIDlet再一次尝试连接(可能是同一用户或者一个新用户)。连接失败,因为这个MIDlet试图连接的SDP记录没有监听器,所以Bluetooth栈除了拒绝连接别无选择。经常发生的情况是,客户端MIDlet接收到两者的SDP记录,但是只选择第一个进行连接,因为它只希望在一个服务器上有一个SDP记录。
在下面的代码示例中了,展示了一个简单的服务器。这个例子关注了必须的close()调用。
例子:
public class SEMCSPPServer extends Thread
{
PRivate StreamConnectionNotifier server = null;
private StreamConnection sppConnection = null;
public SEMCSPPServer()
{
// This will create create an SDP record in the dB
try
{
server = (StreamConnectionNotifier)Connector.open( "BTspp://localhost:ea834a8566aa4e0fb02ce4c1a53700c9;name=SomeServer" );
}
catch( Exception e ) {}
}
public void run()
{
// Wait for connections
try
{
sppConnection = server.acceptAndOpen();
}
catch( Exception e ) { e.printStackTrace(); }
// Let the server do something fun here
try
{
// Open the Streams to be used for communications
InputStream in = sppConnection.openInputStream();
OutputStream out = sppConnection.openOutputStream();
// Let the server do something fun here
while()
{
}
// Server is done, now cleanup
// Close the Streams
try
{
in.close();
}
catch( IOException ioe ) {}
try
{
out.close();
}
catch( IOException ioe ) {}
in = null;
out = null;
}
catch( Exception e ) {}
// Close the Connection
try
{
sppConnection.close();
}
catch( IOException ioe ) {}
sppConnection = null;
// To make it possible for a client to re-connect
// we need to remove the current SDP record
// If the MIDlet ends here we SHOULD still
// close the notifier, but the MIDlet environment will
// clean-up after us
server.close();
} // run
}
自然地,你就拥有了几种类型不同的服务器管理者,它们管理所有的服务器连接,并且使SDP记录重新利用,例如,有一种服务器管理者始终监听连接。例如,在一个多玩家的蓝牙游戏中允许玩家随时进入和退出。
服务器管理者例子:
// A simple server handler
public class SEMCSPPServerHandler
{
private StreamConnectionNotifier server = null;
private StreamConnection sppConnection = null;
public SEMCSPPServerHandler()
{
// This will create create an SDP record in the dB
try
{
server = (StreamConnectionNotifier)Connector.open( "btspp://localhost:ea834a8566aa4e0fb02ce4c1a53700c9;name=SomeServer" );
}
catch( Exception e ) {}
while( true )
{
// Wait for connections
try
{
sppConnection = server.acceptAndOpen();
}
catch( Exception e ) { e.printStackTrace(); }
if( sppConnection != null )
{
SEMCSPPServer sp = new SEMCSPPServer( sppConnection );
sp.start();
sp = null;
}
// The server handler is now ready to deal with new connections
// Note, there is no need to create a new SDP record
}
// Remove the SDP record
server.close();
}
}
// A simple server class to deal with 1 connection
public class SEMCSPPServer extends Thread
{
private StreamConnection sppConnection = null;
public SEMCSPPServer( StreamConnection sppConnection )
{
this.sppConnection = sppConnection;
}
public void run()
{
try
{
// Open the Streams to be used for communications
InputStream in = sppConnection.openInputStream();
OutputStream out = sppConnection.openOutputStream();
// Let the server do something fun here
while()
{
}
// Server is done, now cleanup
// Close the Streams
try
{
in.close();
}
catch( IOException ioe ) {}
try
{
out.close();
}
catch( IOException ioe ) {}
in = null;
out = null;
}
catch( Exception e ) {}
// Close the Connection
try
{
sppConnection.close();
}
catch( IOException ioe ) {}
sppConnection = null;
// The server is no longer active
} // run
}
需要学习的经验
如果Connector. open()调用没有很好的管理,除非退出MIDlet(这种情况下SDP数据库被在一个清空)否则要重新连接到那个SDP记录是不可能的。现实生活中,你必须要退出游戏然后重新启动,这将会使最终用户灰心地离开。
当然,在你可以的应用中可能包括多于一个的SDP记录,但是对于适当的功能性需求要确保MIDlet监听所有的记录。
原文地址:http://developer.sonyeriCSSon.com/site/global/techsupport/tipstrickscode/java
/p_advice_bluetooth_sdp_game+server.jsp
(出处:http://www.knowsky.com)