20:37, 11 May 2011

advertisement
JavaME
TAMZ
Socket-based Network
Communication in
JavaSE and JavaME
Department of Computer Science
VŠB-Technical University of Ostrava
1
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
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)
JavaSE 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
by Roman Szturc 2006 & Pavel Moravec 2008
2
TAMZ
JavaME
Stream Communication (TCP)
socket
bind
connect
listen
client
server
accept
DATA
send/recv
close
Department of Computer Science
VŠB-Technical University of Ostrava
3
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Datagram Communication (UDP)
socket
bind
connect
(a)
send/recv
(a)
read/write
Department of Computer Science
VŠB-Technical University of Ostrava
(b)
DATA
(b) sendto/recvfrom
close
4
by Roman Szturc 2006 & Pavel Moravec 2008
JavaSE TCP/IP Communication (1)
Network communication classes in JavaSE 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([port]);
java.net.MulticastSocket – DatagramSocket used for sending
multicasts (traffic to a group of computers).
java.net.DatagramPacket – block of data to send/receive with
DatagramSocket. We wrap it around a buffer in constructor and if
necessary specify an InetAddress and port of destination
computer: new DatagramPacket(buffer, length, [address, [port]]);
TAMZ
JavaME
JavaSE TCP/IP Communication (2)
java.net.InetAddress – representation of IP address. Instance can
be created by static methods getByName(hostname),
getByAddress(byte[4] addr). Text representation of IP address can
be retrieved back by getHostAddress() and getHostName().
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 accept()
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 to
new URL(url).openConnection();
Department of Computer Science
VŠB-Technical University of Ostrava
6
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
JavaSE 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
Department of Computer Science
VŠB-Technical University of Ostrava
7
by Roman Szturc 2006 & Pavel Moravec 2008
JavaSE TCP Socket Connection
The Socket allows us to connect to given port on a given host.
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); }
JavaSE TCP Server
The ServerSocket listens to traffic on given port on localhost. The accept()
method returns a socket representing client side.
…
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); }
JavaSE TCP Server – MultiThreading
Since all requests in previous example must wait until the server calls
accept again, the processing is delayed. The solution is to use Threads:
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(new 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
}
}
JavaSE UDP Client
The following example shows how we use DatagramSocket to send data to
given server's port. Each datagram is independent and may not be delivered
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); }
JavaSE UDP Server
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.
…
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); }
TAMZ
JavaME
JavaME TCP Socket Connection
Establish a socket connection using Connector and read/write data using
associated input/output streams, which must be closed as well as the
socket when terminating the connection.
String uri = "socket://" + name + ":" + port;
StreamConnection connection = (StreamConnection) //or SocketConnection
Connector.open(uri, Connector.READ_WRITE);
InputStream input
= connection.openInputStream();
OutputStream output = connection.openOutputStream();
// Send a message.
String outgoing = ...
output.write(outgoing.getBytes());
output.flush();
// Receive a response.
byte buffer[] = new byte[SIZE];
int read = input.read(buffer);
Department of Computer Science
VŠB-Technical University of Ostrava
13
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
JavaME TCP Server
The Server Socket listens to traffic on given port on localhost. The MIDP
implementations differ in handling of the server sockets.
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!)
Department of Computer Science
VŠB-Technical University of Ostrava
by Roman Szturc 2006 & Pavel Moravec 2008
14
TAMZ
JavaME
JavaME Server's Request Handler
In order to ensure handling of multiple clients, the request handler is
executed by an independent thread of execution.
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();
}
}
...
Department of Computer Science
VŠB-Technical University of Ostrava
15
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME UDP Client
The following example shows how we use DatagramConnection to send data
to given server's port.
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(); }
JavaME UDP Server
The following example shows how we use DatagramConnection to to listen
on given port. The server changes messages to uppercase.
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();
}
JavaME Servers – Closing Remarks
When running servers on mobile devices with
JavaME 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 JavaME 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)
TAMZ
JavaME
Multi Threading
MULTI
THREADING
Department of Computer Science
VŠB-Technical University of Ostrava
19
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
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
20
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Class Thread
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.
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();
Department of Computer Science
VŠB-Technical University of Ostrava
21
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Interface Runnable
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.
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();
Department of Computer Science
VŠB-Technical University of Ostrava
22
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
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
23
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Synchronization
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.
public class Game {
private Player black, white, previous;
public synchronized void turn(Player player) {
if (player == previous)
throw new IllegalPlayerException(...);
...
Department of Computer Science
VŠB-Technical University of Ostrava
24
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Producer-Consumer Problem
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.
Producer
Consumer
SharedData
public interface SharedData {
public int getSize();
public void put(int[] data);
public int[] get();
}
Department of Computer Science
VŠB-Technical University of Ostrava
25
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Producer
The producer executes a loop in which it puts new items into the data
store.
public class Producer extends Thread {
private SharedData data;
public Producer(SharedData data) { this.data = 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);
}
}
Department of Computer Science
by Roman Szturc 2006 & Pavel Moravec 2008
...
VŠB-Technical
University of Ostrava
26
JavaME
TAMZ
Consumer
The consumer executes a loop in which it removes items from the data
store.
public class Consumer extends Thread {
private SharedData data;
public Consumer(SharedData data) { this.data = 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();
}
}
...
Department of Computer Science
VŠB-Technical University of Ostrava
27
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Naïve Shared Data
Traditional implementation of the SharedData interface seems to be all
right, but ...
public class NaiveSharedData implements SharedData {
private int[] data;
public NaiveSharedData(int count) { data = new int [count]; }
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;
}
... of Computer Science
Department
VŠB-Technical University of Ostrava
by Roman Szturc 2006 & Pavel Moravec 2008
28
TAMZ
JavaME
Putting It All Together
The producer-consumer problem can be assembled by a few lines of
code.
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, e.g. 0 0 1.
...
put
put
got
got
put
...
000
111
001
111
222
Department of Computer Science
VŠB-Technical University of Ostrava
29
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Acquiring a Lock
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.
public class BetterSharedData extends NaiveSharedData {
public synchronized void put(int[] data) {
super.put(data);
}
public synchronized int[] get() {
return super.get();
}
...
put 2 2 2
got 2 2 2
got 2 2 2
Department of Computer Science
VŠB-Technical University of Ostrava
30
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Releasing a Lock (1)
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.
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) {
...
Department of Computer Science
VŠB-Technical University of Ostrava
31
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Releasing a Lock (2)
The InterruptedException is thrown by the wait() method if another thread
interrupts the current thread.
public synchronized int[] get() {
int data[] = null;
try {
while (read)
wait();
data = super.get();
read = true;
notifyAll();
}
catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
Department of Computer Science
VŠB-Technical University of Ostrava
32
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
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
33
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Timer Task
A subclass of TimerTask defines what is to be done. It
declares abstract method run() which has be
implemented by the subclass.
public class DrawerTask extends TimerTask {
private AnimationCanvas canvas;
public DrawerTask(AnimationCanvas canvas) {
this.canvas = canvas;
}
public void run() {
canvas.drawNextFrame();
}
}
Department of Computer Science
VŠB-Technical University of Ostrava
34
by Roman Szturc 2006 & Pavel Moravec 2008
JavaME
TAMZ
Animation Canvas
The drawNextFrame() is invoked repeatedly by a DrawerTask.
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();
}
...
Department of Computer Science
VŠB-Technical University of Ostrava
35
by Roman Szturc 2006 & Pavel Moravec 2008
TAMZ
JavaME
Timer
The timer executes its task reapeatedly, which in turn affects the
animation canvas, forcing it to repaint.
AnimationCanvas canvas = new AnimationCanvas();
TimerTask task = new DrawerTask(canvas);
Timer timer = new Timer();
// Repeat the task each 1 second.
timer.schedule(task, 0, 1000);
Department of Computer Science
VŠB-Technical University of Ostrava
36
by Roman Szturc 2006 & Pavel Moravec 2008
Download