While PDAs, cell phones, and MP3 players are more likely to act as clients than servers, the opposite is true for refrigerators, laboratory sensors, hotel door locks, and similar embedded devices. The natural mode of operation for these devices is to run a server providing their current status information that interested clients can query. The ServerSocketConnection class meets these needs.
Server socket URLs look like socket://:13. All you have to specify is the port to listen on (13, in this example).
The fundamental operation of a server socket is to listen for and accept incoming connections. Server sockets themselves do not send or receive data. The ServerSocketConnection class does not extend StreamConnection, and you cannot use Connectors open stream methods to open one. You must open the connection and cast it to ServerSocketConnection:
ServerSocketConnection server = (ServerSocketConnection) Connector.open("socket://:37");
Next, you invoke the acceptAndOpen( ) method to receive an incoming connection:
public StreamConnection acceptAndOpen( ) throws IOException
You can then use the methods of StreamConnection to communicate with the remote client.
The acceptAndOpen( ) method blocks while waiting for incoming connections. You probably want to put it in a separate thread.
Example 24-5 demonstrates with a simple J2ME time server. The time protocol responds to each incoming connection by sending it the current time at the server. The time is measured in seconds since midnight, January 1, 1900. It is represented as a 4-byte big-endian unsigned int. Java doesn have unsigned data types, so the program has to do the calculations using longs and then select the low-order four bytes of the resulting number manually. Theres no local interface here. The startApp( ) method spawns a thread that constantly listens for incoming connections, responds to each one, and then closes the connections.
import javax.microedition.midlet.*; import javax.microedition.io.*; import java.io.*; import java.util.Date; public class TCPTimeServer extends MIDlet { private ServerSocketConnection server; // The time protocol sets the epoch at 1900, // the java Date class at 1970. This number // converts between them. private long differenceBetweenEpochs = 2208988800L; protected void startApp( ) { try { server = (ServerSocketConnection) Connector.open("socket://:37"); Runnable r = new Runnable( ) { public void run( ) { while (true) { try { StreamConnection conn = server.acceptAndOpen( ); Date now = new Date( ); long msSince1970 = now.getTime( ); long secondsSince1900 = msSince1970/1000L + differenceBetweenEpochs; DataOutputStream out = conn.openDataOutputStream( ); // write the low-order four bytes out.write( (int) ((secondsSince1900 >>> 24) & 0xFFL)); out.write( (int) ((secondsSince1900 >>> 16) & 0xFFL)); out.write( (int) ((secondsSince1900 >>> 8) & 0xFFL)); out.write( (int) (secondsSince1900 & 0xFFL)); out.close( ); } catch (IOException ex) { } } } }; Thread t = new Thread(r); t.start( ); } catch (IOException ex) { // not much we can do about this here } } protected void pauseApp( ) {} protected void destroyApp(boolean unconditional) { try { server.close( ); } catch (IOException ex) { // We tried } } } |
You can omit the port in the connector URL. That is, socket://: is an acceptable URL to open a server socket. If you omit the port, Java picks any available port to start listening on. You can find out which port it chose with the getLocalPort( ) method:
public int getLocalPort( ) throws IOException
You can also find out the local IP address using the getLocalAddress( ) method:
public String getLocalAddress( ) throws IOException