Department of Computer Science VŠB-Technical University of Ostrava
1
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Socket-based Network
Communication in
J2SE and J2ME
Department of Computer Science VŠB-Technical University of Ostrava
2
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
C/C++ BSD Sockets in POSIX
POSIX functions allow to access network connection
in the same way as regular files:
There are special functions for opening the connections,
the connection is known in POSIX as socket and may be
used for different types of communication – inter-process
communication on the same machine, different network
protocols, etc.
Socket- and protocol-specific parameters are set and
retrieved by calling special functions
Data transfer is done by specific functions or in regular way
(read, write)
J2SE copies this approach in Object-oriented way to a
degree (methods have similar/same names as POSIX
functions).
Department of Computer Science VŠB-Technical University of Ostrava
3
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Stream Communication (TCP)
socket
bind
connect listen
accept
close
DATA send/recv
client server
Department of Computer Science VŠB-Technical University of Ostrava
4
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Datagram Communication (UDP)
socket
bind connect
close
(b) sendto/recvfrom
(a) (b)
send/recv
(a)
read/write DATA
J2SE TCP/IP Communication (1)
Network communication classes in J2SE can be found
in java.net namespace. However, many related classes
do not have a common parent other then Object:
java.net.Socket
– basic client socket for TCP connection. Used to access remote services; we usually supply destination address and port in constructor:new Socket(host, port);
java.net.DatagramSocket
– socket for sending and receiving UDP datagrams, we supply local port in constructor when necessary:new DatagramSocket(host, port);
java.net.MulticastSocket
–DatagramSocket
used for sending multicasts (traffic to a group of computers).
java.net.DatagramPacket
– block of data tosend/receive
withDatagramSocket.
We wrap it around a buffer in constructor and if necessary specify anInetAddress
and port of destinationcomputer:
new DatagramPacket(buffer, length, [address, [port]]);
Department of Computer Science VŠB-Technical University of Ostrava
6
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
J2SE TCP/IP Communication (2)
java.net.InetAddress
– representation of IP address. Instance can be created by static methodsgetByName(hostname),
getByAddress(byte[4] addr)
. Text representation of IP address can be retrieved back bygetHostAddress()
andgetHostName()
.
java.net.ServerSocket
– basic server socket for TCP connection.We need to specify at least the local port the server will be listening at and number of queued requests:
new ServerSocket(port [, backlog]);
When we want to retrieve a queued connection, we call the
listen()
method on server socket.
java.net.URL
– class representing the URL, usually "http://...".
java.net.URLConnection
– basic abstract class for URL-based connections. Corresponding sub-class is opened using call tonew URL(url).openConnection();
Department of Computer Science VŠB-Technical University of Ostrava
7
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
J2SE Sockets – Remarks
The socket operations are blocking, i.e. the thread
execution will stop until the socket operation is finished.
Since non-blocking sockets do not exist in Java, we can
use a workaround by calling setSoTimeout(ms). In case
the timeout is reached, java.net.SocketTimeoutException
is thrown and can be caught.
Several connection/socket parameters can be
set/retrieved by calling various set*/get* methods.
Both connect and bind methods can be called, if we do
not specify the needed parameters in constructor, but
we need to specify an InetAddress + port or SocketAddress
J2SE TCP Socket Connection
try {
s=new Socket(host,port);
BufferedReader sis = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter os = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader is = new BufferedReader(new InputStreamReader(s.getInputStream()));
String l;
do {
System.out.println("Type a line to send to server.");
l=sis.readLine();
os.write(l);
os.newLine();
os.flush();
System.out.println("Server: " + is.readLine());
} while (!l.equals("exit") && !l.equals("down"));
s.close();
} catch (IOException e) { System.out.println(e); }
The Socket allows us to connect to given port on a given host.
J2SE TCP Server
… try {
ServerSocket s=new ServerSocket(port); Socket cs;
do {
cs=s.accept();
BufferedReader is = new BufferedReader
(new InputStreamReader(cs.getInputStream()));
BufferedWriter os = new BufferedWriter
(new OutputStreamWriter(cs.getOutputStream()));
do {
msg=is.readLine();
os.write(String.valueOf(msg.length()));
os.newLine(); os.flush();
} while (!msg.equals("exit") && !msg.equals("down"));
cs.close();
} while (!msg.equals("down"));
s.close();
} catch (IOException e) { System.out.println(e); }
The ServerSocket listens to traffic on given port on localhost. The accept() method returns a socket representing client side.
J2SE TCP Server – MultiThreading
public class MyApplication implements Runnable { protected Socket cs; static ServerSocket s;
static int port=8000;
public static void main(String[] args) { Socket cs;
try {
s=new ServerSocket(port);
do {cs=s.accept(); new Thread(MyApplication(cs)).start();
} while (true);
} catch (IOException e) {if(!e instanceof SocketException){System.out.println(e);}}
}
public MyApplication(Socket cs) {this.cs=cs;}
public void run() {
/* Violet bold text from previous slide */
if (msg.equals("down")) s.close(); //Closes main socket to terminate the application }
}
Since all requests in previous example must wait until the server calls accept again, the processing is delayed. The solution is to use Threads:
J2SE UDP Client
String data; //Will be set later, eg. by reading from System.in int port=8000;
String server="www.cs.vsb.cz";
… try {
DatagramSocket s=new DatagramSocket();
DatagramPacket p = new DatagramPacket(data.getBytes(), data.length(),
InetAddress.getByName(server), port);
s.send(p);
s.receive(p);
reply=new String(p.getData(),0,p.getLength());
System.out.println("Reply arrived from "+ p.getAddress() +" : "+ p.getPort()+" > " + reply);
s.close();
} catch (IOException e) { System.out.println(e); }
The following example shows how we use
DatagramSocket
to send data to given server's port. Each datagram is independent and may not be deliveredJ2SE UDP Server
… try {
DatagramSocket s=new DatagramSocket(port);
DatagramPacket p;
String msg;
do {
p=new DatagramPacket(new byte[512], 512); // new instance each time due to buffer length s.receive(p);
msg = new String(p.getData(),0,p.getLength());
System.out.println("Datagram from " + p.getAddress() + " : " + p.getPort() + " > " + msg);
p.setData(msg.toUpperCase().getBytes());
p.setLength(msg.length());
s.send(p);
} while (!msg.equals("down"));
s.close();
} catch (IOException e) { System.out.println(e); }
We do not have a specific class for datagram servers, since it is not needed.
The following example shows how we use
DatagramSocket
on server's port.Department of Computer Science VŠB-Technical University of Ostrava
13
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
J2ME TCP Socket Connection
String uri = "socket://" + name + ":" + port;
StreamConnection connection = (StreamConnection)
Connector.open(uri, Connector.READ_WRITE);
InputStream input = connection.openInputStream();
OutputStream output = connection.openOutputStream();
// Send a message.
String outgoing = ...
output.write(outgoing.getBytes());
// Receive a response.
byte buffer[] = new byte[SIZE];
int read = input.read(buffer);
Establish a socket connection using Connector and read/write data using associated input/output streams.
Department of Computer Science VŠB-Technical University of Ostrava
14
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
J2ME TCP Server
MIDP 1.0 – the socket is reused for incomming connection
StreamConnectionNotifier serverSocket =
(StreamConnectionNotifier) Connector.open("serversocket://:12345");
StreamConnection conn = serverSocket.acceptAndOpen();
MIDP 2.0 – a new socket is created.
ServerSocketConnection scn =
(ServerSocketConnection) Connector.open("socket://:12345");
SocketConnection sc = (SocketConnection) scn.acceptAndOpen();
Both the device and the service operator must support servers on
mobile devices to make it work (e.g. no private IP addresses!)
The Server Socket listens to traffic on given port on localhost. The MIDP implementations differ in handling of the server sockets.
Department of Computer Science VŠB-Technical University of Ostrava
15
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
J2ME Server's Request Handler
public class EchoRequestHandler extends Thread {
public void run() {
try {
InputStream input = serverSocket.getInputStream();
OutputStream output = serverSocket.getOutputStream();
int read;
byte data[] = new byte[BUFFER_SIZE];
while ((read = input.read(data)) != -1) {
output.write(data, 0, read);
output.flush();
}
}
...
In order to ensure handling of multiple clients, the request handler is executed by an independent thread of execution.
J2ME UDP Client
String data; //Will be set later, eg. by reading from System.in int port=8000; String server="www.cs.vsb.cz";
… try {
DatagramConnection dc = (DatagramConnection)
Connector.open("datagram://" + server + ":" + port);
Datagram dg = dc.newDatagram(100);
byte[] bytes = message.getBytes();
dc.send(dc.newDatagram(bytes, bytes.length));
dc.receive(dg);
if (dg.getLength() > 0) {
System.err.println("Message received - " + new String(dg.getData(), 0, dg.getLength()));
}
} catch (ConnectionNotFoundException cnfe) {
//Connection not successful – server is possibly not running, do something about it } catch (IOException e) { e.printStackTrace(); }
The following example shows how we use
DatagramConnection
to send data to given server's port.J2ME UDP Server
int port=8000;
try {
DatagramConnection dc = (DatagramConnection)Connector.open("datagram://:" + port);
while (true) {
Datagram dg = dc.newDatagram(100);
dc.receive(dg);
address = dg.getAddress();
if (dg.getLength() > 0) {
String message = new String(dg.getData(), 0, dg.getLength()).toUpperCase();
System.err.println("Message received: " + message);
byte[] bytes = message.getBytes();
dc.send(dc.newDatagram(bytes, bytes.length));
} }
} catch (IOException e) {
//Binding not successful – another server is possibly running on the same port e.printStackTrace();
}
The following example shows how we use
DatagramConnection
to to listen on given port. The server changes messages to uppercase.J2ME Servers – Closing Remarks
When running servers on mobile devices with J2ME
we have to keep in mind following issues:
Local socket-based connections between applications may
not pose a problem, but the device must be able to run
more than one J2ME application/MIDlet at a time (we do
not have to use sockets to communicate between threads).
Remote applications must know the IP address of the
device acting as server, which may pose a problem
(in MIDP 2.0 we can call getLocalAddress() on an opened
server socket ).
To be accessible from Internet, the device must have a
public IP address (the addresses containing 10.*.*.*,
172.16.*.* – 172.31.*.*, 192.168.*.* and 169.254.*.* are
not accessible from Internet, since they are private)
Department of Computer Science VŠB-Technical University of Ostrava
19
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Multi Threading
MULTI
THREADING
Department of Computer Science VŠB-Technical University of Ostrava
20
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Threads
There is often need to turn a program into separate, independently running subtasks. Each of these independent subtasks is called a thread, and is programmed as if each thread runs by itself and has the CPU to itself. The thread model is a programming convenience to simplify juggling several operations at the same time within a single program. There is several reasons why to do this.
● There can be one thread controlling and responding to a GUI, while another thread carries out the tasks or computations requested, while a third thread does file I/O, all for the same program.
● Some programs are easier to write if they are split into threads. The classic example is the server part of a client/server. When a request comes in from a client, it is very convenient if the server can spawn a new thread to process that one request.
Department of Computer Science VŠB-Technical University of Ostrava
21
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Class Thread
public class CountDownThread extends Thread { private static int threads = 0;
private int thread = threads++;
public void run() {
for (int i = MAX_COUNT; i > 0; i--) System.out.println("thread #" + thread + ": " + i);
}}
Thread thread = new CountDownThread();
thread.start();
The simplest way to create a thread is to inherit from class java.lang.Thread. The most important method for Thread is run(), which is the code that will be executed simultaneously with the other threads in a program.
Department of Computer Science VŠB-Technical University of Ostrava
22
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Interface Runnable
public class CountDownThread implements Runnable { private static int threads = 0;
private int thread = threads++;
public void run() {
for (int i = MAX_COUNT; i > 0; i--) System.out.println("thread #" + thread + ": " + i);
}}
Thread thread = new Thread(new CountDownThread());
thread.start();
Sometimes it is impossible or inconvenient to inherit from Thread class.
The java.lang.Runnable interface, declaring the run() method, can be implemented in these cases.
Department of Computer Science VŠB-Technical University of Ostrava
23
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
The Life Cycle of a Thread
A thread goes through several states during its life cycle:
● Creating
When a thread is created, it is merely an empty object. No system resources are allocated. The thread in this can be only started.
● Starting
The start() method creates the system resources necessary to run the thread, schedules the thread to run, and calls the thread's run() method.
● Making a Thread Not Runnable
A thread becomes Not Runnable when one of these events occurs: its sleep() or wait() method is invoked.
● Stopping
A program does not stop a thread directly. Rather, a thread arranges for its own death by leaving its run() method.
Department of Computer Science VŠB-Technical University of Ostrava
24
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Synchronization
public class Game {
private Player black, white, previous;
public synchronized void turn(Player player) { if (player == previous)
throw new IllegalPlayerException(...);
...
There are many interesting situations where separate, concurrently running threads do share data and must consider the state and activities of other threads. Java provides a synchronization mechanism based on monitors. Each object in Java has a lock and a monitor to manage the lock. A block marked as synchronized forces any thread wishing to enter the block to acquire corresponding lock first. If another thread already holds the lock, the acquiring thread will block until the lock will be released. The lock is released when the thread leaves the block.
Department of Computer Science VŠB-Technical University of Ostrava
25
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Producer-Consumer Problem
public interface SharedData { public int getSize();
public void put(int[] data);
public int[] get();
}
The producer-consumer problem is a classic synchronization problem.
The producer and consumer processes share a common data. The producer executes a loop in which it puts new items into the data and the consumer executes a loop in which it removes items from the data.
Consumer Producer
SharedData
Department of Computer Science VŠB-Technical University of Ostrava
26
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Producer
public class Producer extends Thread { private SharedData data;
public void run() {
for (int i = 0; i < 10; i++) {
int[] array = new int[data.getSize()];
System.out.print("put");
for (int j = 0; j < array.length; j++) { array[j] = i;
System.out.print(" " + array[j]);
}
System.out.println();
data.put(array);
} } ...
The producer executes a loop in which it puts new items into the data store.
Department of Computer Science VŠB-Technical University of Ostrava
27
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Consumer
public class Consumer extends Thread { private SharedData data;
public void run() {
for (int i = 0; i < 10; i++) { int[] array = data.get();
System.out.print("got");
for (int j = 0; j < array.length; j++) System.out.print(" " + array[j]);
System.out.println();
} } ...
The consumer executes a loop in which it removes items from the data store.
Department of Computer Science VŠB-Technical University of Ostrava
28
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Naïve Shared Data
public class NaiveSharedData implements SharedData { private int[] data;
public void put(int[] data) {
for (int i = 0; i < data.length; i++) this.data[i] = data[i];
}
public int[] get() {
int[] data = new int[this.data.length];
for (int i = 0; i < data.length; i++) data[i] = this.data[i];
return data;
} ...
Traditional implementation of the SharedData interface seems to be all right, but ...
Department of Computer Science VŠB-Technical University of Ostrava
29
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Putting It All Together
SharedData data = new NaiveSharedData(3);
Producer producer = new Producer(data);
Consumer consumer = new Consumer(data);
producer.start();
consumer.start();
Output produced by the program is incorrect, because it contains inconsisten sequence 0 0 1.
The producer-consumer problem can be assembled by a few lines of code.
...put 1 1 1 got 0 0 1 got 1 1 1 put 2 2 2 ...
Department of Computer Science VŠB-Technical University of Ostrava
30
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Acquiring a Lock
public class BetterSharedData extends NaiveSharedData { public synchronized void put(int[] data) {
super.put(data);
}
public synchronized int[] get() { return super.get();
}
The code segments within a program that access the same object from separate, concurrent threads are called critical sections. A critical is identified with the synchronized keyword. A lock is associated with every object that has synchronized code.
...put 2 2 2 got 2 2 2 got 2 2 2
Department of Computer Science VŠB-Technical University of Ostrava
31
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Releasing a Lock (1)
public class PerfectSharedData extends BetterSharedData { private boolean read = true;
public synchronized void put(int[] data) { try {
while (!read) wait();
super.put(data);
read = false;
notifyAll();
}
catch (InterruptedException e) { ...
A thread releases an object's lock when it enters into wait() method of the object. The wait() method causes the thread to wait until another thread invokes the notify() or the notifyAll() method for the object.
Department of Computer Science VŠB-Technical University of Ostrava
32
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Releasing a Lock (2)
public synchronized int[] get() { int data[] = null;
try {
while (read) wait();
data = super.get();
read = true;
notifyAll();
} catch (InterruptedException e) { e.printStackTrace();
}
return data;
}
The InterruptedException is thrown by the wait() method if another thread interrupts the current thread.
Department of Computer Science VŠB-Technical University of Ostrava
33
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Scheduling Tasks
There are two classes, Timer and TimerTask, to facilitate running of tasks in a background thread.
● Scheduling one-time tasks
Executes a task after specified delay.
● Scheduling repeating tasks
Executes a task at regular intervals. There are two variations for scheduling repeating tasks.
● Fixed-delay
Each execution of a task is based solely on how long it was since the previous task finished.
● Fixed-rate
Each execution of a task is based on when the first task started and the requested delay between tasks.
Department of Computer Science VŠB-Technical University of Ostrava
34
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Timer Task
public class DrawerTask extends TimerTask { private AnimationCanvas canvas;
public DrawerTask(Canvas canvas) { this.canvas = canvas;
}
public void run() {
canvas.drawNextFrame();
} }
A subclass of TimerTask defines what is to be done. It declares abstract method run() which has be implemented by the subclass.
Department of Computer Science VŠB-Technical University of Ostrava
35
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Animation Canvas
public class AnimationCanvas extends Canvas { private Image[] frames = new Image[FRAMES];
int currentFrame = 0;
public AnimationCanvas() throws IOException { for (int i = 0; i < frames.length; i++) {
frames[i] = Image.createImage("/frame" + (i+1) + ".png");
} }
public void drawNextFrame() {
currentFrame = (currentFrame+1)%frames.length;
repaint();
} ...
The drawNextFrame() is invoked repeatedly by a DrawerTask.
Department of Computer Science VŠB-Technical University of Ostrava
36
J2ME TAMZ
by Roman Szturc 2006 & Pavel Moravec 2008
Timer
AnimationCanvas canvas = new AnimationCanvas();
TimerTask task = new DrawerTask(canvas);
Timer timer = new Timer();
// Repeat the task each 1 second.
timer.schedule(task, 0, 1000);
The timer executes its task reapeatedly, which in turn affects the animation canvas, forcing it to repaint.