Browse DevX
Sign up for e-mail newsletters from DevX


Master Networking in J2ME for Well-connected Mobile Apps : Page 3

J2ME supports a Generic Connection Framework that provides a variety of standard network connectivity options. Find out how to take advantage of J2ME networking in your applications.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Digging into Datagrams
It is quite possible for someone to have worked with Java for some time without ever needing to understand or use datagrams. For mobile devices, however, datagrams offer some advantages in that they are rather lightweight when compared to TCP-based connections such as sockets. User Datagram Protocol, UDP, is one of the more common datagram protocols. However, because most datagram protocols follow the same basic principals as to their usage, the GCF is able to support datagrams generically.

Datagrams are based on a connection-less paradigm, which means that a conversation is not established between two systems. Instead, datagrams are blindly transmitted across a network connection. To transmit a datagram from one system to another, an application creates a datagram and sends it to the intended target. This is a rather simple process in J2ME. However, there is a caveat to using datagrams in that they offer no guarantee or acknowledgement as to whether the datagram actually reached the intended recipient. As a result, a datagram implementation must either not care if the recipient actually receives the data 100 percent of the time, or an acknowledgement/handshake must be implemented manually by the application.

Using Datagrams
The following example shows how to create a datagram and send it to a specific IP address.

try { DatagramConnection dgc = (DatagramConnection) Connector.open("datagram://localhost:9001"); try { byte[] payload = "Test Message".getBytes(); Datagram datagram = dgc.newDatagram(payload, payload.length); dgc.send(datagram); } finally { dgc.close(); } } catch (IOException x) { x.printStackTrace(); }

In this example, a MIDlet creates a Datagram containing the text "Hello from a Datagram" and sends it to an application listening for datagrams on the local machine on port 9001. This example will execute just fine even if there is no application running to receive the datagram, thus demonstrating the connection-less nature of datagrams. The sender has no indication that the datagram was consumed by the target system.

Next I show how an application might receive the datagram sent by the previous code snippet.

try { DatagramConnection dgc = (DatagramConnection) Connector.open("datagram://:9001"); try { int size = 100; Datagram datagram = dgc.newDatagram(size); dgc.receive(datagram); System.out.println( new String(datagram.getData()).trim()); } finally { dgc.close(); } } catch (IOException x){ x.printStackTrace(); }

In the receive example, a datagram connection is established on port 9001. A datagram is created with a size of 100 bytes; if a received datagram contains more than 100 bytes, any data beyond the 100-byte mark is ignored. Once the datagram is created the receive() method is called, putting the thread in a wait state until a datagram is received. When a datagram is received, the payload is extracted from the datagram container and printed to the console.

In order to run the send and the receive examples, two instances of a MIDlet can be run from the Wireless Toolkit, one to perform the receive and one to perform the send.

Socket To Me
Another type of connection commonly available on J2ME devices is the TCP-based socket connection. Sockets are different than datagrams because they use a connection-based paradigm to transmit data. This means that both a sender and a receiver must be running and establish a communication channel for data to be exchanged. To use a real-world analogy, a socket connection is like calling a friend on the telephone. If the friend does not answer, a conversation cannot take place. Datagrams on the other hand are more like sending a letter to a friend, where a note is placed into an envelope, addressed, and mailed.

The following code demonstrates how to set up a listener to monitor a port for an inbound socket connection.

try { ServerSocketConnection ssc = (ServerSocketConnection) Connector.open("socket://:9002"); StreamConnection sc = null; InputStream is = null; try{ sc = ssc.acceptAndOpen(); is = sc.openInputStream(); int ch = 0; StringBuffer sb = new StringBuffer(); while ((ch = is.read()) != -1){ sb.append((char)ch); } System.out.println(sb.toString()); } finally{ ssc.close(); sc.close(); is.close(); } } catch (IOException x) { x.printStackTrace(); }

In this example a ServerSocketConnection is opened on port 9002. This type of connection is used for sole purpose of listening for an inbound socket connection. The code goes into a wait state when the acceptAndOpen() method is called. When a socket connection is established, the acceptAndOpen() method returns with an instance of a SocketConnection. Opening an input stream on this connection allows data to be read from the transmission.

The next example demonstrates the code required by the client to initiate the socket connection.

try{ SocketConnection sc = (SocketConnection) Connector.open("socket://localhost:9002"); OutputStream os = null; try{ os = sc.openOutputStream(); byte[] data = "Hello from a socket!".getBytes(); os.write(data); } finally{ sc.close(); os.close(); } } catch (IOException x){ x.printStackTrace(); }

In this example a SocketConnection is established on port 9002 of the local machine. When using sockets, this is the point on the server side that the acceptAndOpen() method returns. If the connection is successfully opened, the OutputStream is obtained and a message is written to the stream. Note that because sockets are connection based, if there is no server listening for an incoming socket connection an exception will be thrown.

Reading Web Content
The last example will cover reading data using the MIDP HttpConnection. Note that this connection interface is not part of the CLDC or CDC, but is defined rather in the MIDP and Personal Profiles themselves. The behavior of HttpConnection is one that combines an InputStream and an OutputStream into a single connection. A single HttpConnection may open and use exactly one OutputStream and exactly one InputStream. The order in which the streams are used is important as well. The OutputStream, if used, must be used before the InputStream. Once the streams have been used the connection should be closed and a new HttpConnection should be opened to continue communications if necessary. This follows the HTTP request-response paradigm.

The HttpConnection is a bit more tricky to use than the socket or datagram connections because there is a lot that happens behind the scenes. There are three states to an HttpConnection:

  • Setup
  • Connected
  • Closed
The setup state is the first state encountered after a connection is opened. While in this state, connection parameters can be set such as the request method (GET, POST or HEAD) using the setRequestMethod() method or any header properties using the setRequestProperty() method.

The transition from setup to connected is triggered by any methods that cause data to be sent to the server. The following is a list of methods that cause this transition.

  • openInputStream
  • openDataInputStream
  • getLength
  • getType
  • getEncoding
  • getHeaderField
  • getResponseCode
  • getResponseMessage
  • getHeaderFieldInt
  • getHeaderFieldDate
  • getExpiration
  • getDate
  • getLastModified
  • getHeaderField
  • getHeaderFieldKey
Once the connection transitions to the connected state, any calls to setRequestMethod() and setRequestProperty() will throw an IOException. The state transition from setup to connected reflects the underlying handshake of the HttpConnection as headers are sent to the server and the connection prepares to send data. The following example demonstrates reading Web content from an HttpConnection.

HttpConnection c = null; InputStream is = null; StringBuffer sb = new StringBuffer(); try { c = (HttpConnection)Connector.open( "http://www.gearworks.com”, Connector.READ_WRITE, true); c.setRequestMethod(HttpConnection.GET); //default is = c.openInputStream(); // transition to connected! int ch = 0; for(int ccnt=0; ccnt < 150; ccnt++) { // get the title. ch = is.read(); if (ch == -1){ break; } sb.append((char)ch); } } catch (IOException x){ x.printStackTrace(); } finally{ try { is.close(); c.close(); } catch (IOException x){ x.printStackTrace(); } } System.out.println(sb.toString());

In this example, the server at www.gearworks.com is contacted. Because this is an HttpConnection and no port is specified, port 80 is used by default. The request method is set to GET (note GET is the default and is explicitly set here only for the example).

Thanks for your registration, follow us on our social networks to keep up-to-date