CS4812 Java

advertisement
GSAMS Java
Java Networking
Networking Topics
• Overview: A Short History of Java Networking
– Where from; where to; “Are We There Yet?”
• Competing Networking Models: OSI v. Internet
– Whose Kung Fu is Better?
• Network Protocols in Java:
–
–
–
–
TCP
UDP
Multicast
Threaded and Non-Threaded examples
• Remote Method Invocation (RMI)
A Short History of Java Networking
• The Dark Ages: C/C++ Networking and the Need for
Change
– Before Java, simple network connectivity required lots of
code.
– C/C++ provided many, many choices/options for networking
• Good for C programmers.
• Most programmers did not use all these options.
• Java 1.0
Reflects Java’s non-academic motivations
– Basic networking capability with high level abstraction of URL
handlers.
– Low level choices were missing (e.g., connection timeouts.)
– Raw socket classes were final--java.net.Socket and
java.net.ServerSocket could not be extended.
– “One shot” implementations with java.net.SocketImpl allowed
only one implementation in each VM.
A Short History of Java Networking
• JDK 1.1 (the big leap)
– Added four common socket options.
– Allowed raw data manipulations within high-level
abstractions.
– Removed final designations.
– Added multicast connections (previously limited to LAN
and/or external native calls).
• JDK 1.2 (a second big leap)
– Addition of fine-grained Java Security Model.
• ability to control processes/connections/ports with very
fine granular control over details.
– Added functionality to APIs.
Competing Networking Models:
OSI vs. Internet
Whose Kung Fu is Better?
• Two competing models are used to describe
networking
– Open Systems Interconnection (OSI) architecture
– Internet Architecture
• Open Systems Interconnection Standard
– partitions network connectivity into seven layers.
– published by OSI and International Telecommunications
Union (ITU) in series of “X dot” standards: X.25, X.400,
etc.
• Internet Architecture Standard
– also known as “TCP/IP architecture” after its two key
protocols
– evolved from packet-switched ARPANET of DoD
– Internet Engineering Task Force (IETF) maintenance.
A Comparison of the OSI Seven Layer Model
and the Taco Bell Seven Layer Burrito
Application
Presentation
Session
Transport
Network
Data in use
Syntax
Packet recovery;
sessions between applications
Message quality; end-to-end
error correction
Packet routing; network
connections
Sour Cream
Cheese
Guacamole
Tomatoes
Lettuce
Data Link
Bit level organization; reliability
Seasoned Rice
Physical
Media, electrical properties
Refried Beans
End Host
Application
OSI in Action
End Host
Network traffic in the OSI model
must always travel up and down the
protocol stack to be routed.
Application
Presentation
Presentation
Session
Session
Transport
Nodes in Network
Transport
Network
Network
Network
Network
Data Link
Data Link
Data Link
Data Link
Physical
Physical
Physical
Physical
Internet Architecture Model
Design theory: “rough consensus and running code”
Application Protocols
Transport Protocols
(TCP/UDP)
Internet Protocol (IP)
Network Protocols
The IETF culture requires
that new layers provide a
protocol specification and at
least two or three running
implementations.
Likely, the four layer model
will not grow in complexity
(unless the internet does
first.)
Internet Architecture Model
The Internet Architecture is also flexible; applications can reach the
network layer directly, or work through protocols such as TCP/UDP and IP
APPLICATION
TCP UDP
IP
NETWORK
Internet Architecture Model
Transport through each layer requires the use of additional headers.
Application Layer
DATA
Transport Layer
Internet Layer
Network Layer
HEADER
HEADER
DATA
HEADER
HEADER
DATA
HEADER
HEADER
DATA
Network Protocols in Java
In terms of protocols and services, Java offers API support for three
basic types of connectivity:
TCP -- Transport Control Protocol
UDP -- User Datagram Protocol
java.net
package
Mcast -- Multicast Protocol.
-- Basic Terminology -A Socket is an abstraction of a "communications link" between
machines over some network.
Socket communication is the same regardless of whether the
network connection is via a phone line, cable modem, ethernet, or
fiber-optic line.
A packet is a discrete quantity of information suitable for routed
transport over a shared network. Packet sizes are limited, so a
packet may be a fragment of a large file or message.
Basic Terminology (cont’d)
Naming and Addressing
The “IPv4” addressing scheme uses 32-bit addresses, often
presented as a set of four octets.
Read from left to right, we progressively define a particular machine:
192.168.1.200
The “dotted quad” or “dotted decimal” format is quite common.
Numbering is controlled by the Internet Assigned Numbers Authority
(IANA), and later the Internet Corporation for Assigned Names and
Numbers (ICANN).
IP Address Classes
A
127.0.0.0 and below
First bit == 0
B
127.0.1.0 to 191.255.255.255
First bits == 1 0
C
192.0.1.0 to 223.255.255.255
First bits == 1 1 0
D
Not allocated to networks -- mcast
First bits == 1 1 1 0
E
240.0.0.0 and above; not assigned
First bits == 1 1 1 1
Special numbers:
127.0.0.1 -- used for loopback addresses
192.168.x.x -- class B private networks
10.x.x.x. -- class A private networks
IP Address Classes
The IPv4 address scheme is limited by potentially wasteful address
allocation. For example, the jump from class C (one octet, or ~254
addresses) to class B (two octets, or ~65334 addresses) is quite
large.
So, a company with more than 250 computers might request a class
B address, but use far less than the ~65,000 possible combinations.
This inefficiency consumes the address space quickly.
Solutions include more efficient number allocations, ip chaining
(firewalls), and migration to IPv6 (128 bit address), . . . even IPv8.
Java’s underlying native code has support for IPv6, so it will be ready
if/when companies (notably Cisco) decide to embrace IPv6.
IP Addresses: Names
To make IP addresses readable, a table of names is used to represent
IP numbers. The names are in a hierarchical order; however, there is
no one-to-one mapping between name hierarchies and dotted quad
number hierarchies.
DNS, or Domain Name Service, provides a name to IP addressing
service.
.
net
gov
mil
(Root)
org
com
edu
On a Unix machine, one often uses “nslookup” or some similar
program to covert between names and numbers.
Ports
Most computers have a single network connection used for all data.
Most operating systems allow multi-tasking, so several network applications
can be running at once. How does the computer know which application gets
the data?
Ports allow us to specify specific applications on the host. The TCP and UDP
protocols attach port information (16 bit number) to each packet.
Machine2
Machine1
Machine3
Thus, when creating connections between computers, we need an IP
address as well as the port to specify the machine and client process
The java.net.* Package
Key Classes:
java.net.InetAddress
IP Address structures, and services
java.net.ServerSocket
This class implements server sockets.
java.net.Socket
This class implements client sockets (also called
just "sockets").
java.net.URL
Class URL represents a Uniform Resource Locator,
a pointer to a "resource" on the World Wide Web.
Address representations
java.net.InetAddress:
-- A class representing an IP address
-- Performs validity checking on IP names
-- Thus, there are no public constructors!
-- Instead, just call a static class method
to obtain an InetAddress:
InetAddress
has no public
constructors
since it performs
validity checking
of all IP names
import java.net.*;
public class MyMachineName {
public static void main (String arg[]){
InetAddress local = null;
try {
local = InetAddress.getLocalHost();
} catch (UnknownHostException e){
System.err.println ("Identity Crisis!");
System.exit(0);
}
String strAddress = local.getHostName();
System.out.println ("Local Host = " + strAddress);
}
}
Converting IP Numbers to Strings
import java.net.*;
This does things
public class MyMachineName {
the hard way!
public static void main (String arg[]){
InetAddress local = null;
Just call
try {
getHostAddress()
local = InetAddress.getLocalHost();
instead!
} catch (UnknownHostException e){
System.err.println
Lesson: Java’s
("Identity Crisis!");
net package has most
System.exit(0);
every method you
}
will need!
byte[] b = local.getAddress();
String strAddress=“”;
for (int i = 0; i < b.length; i++)
strAddress += ((int)255 & b[i]) + “.”;
System.out.println (“Local = “ + strAddress);
}
}
Other InetAddress Services
public boolean isMulticastAddress();
static InetAddress[] getAllByName(String host);
Determines all the IP addresses of a host,
given the host's name.
static InetAddress getByName(String host);
Determines the IP address of a host,
given the host's name.
Let’s duplicate the basic service of the Unix command “nslookup” in
Java. This will allow us to convert any IP name into its valid IP
number. (We won’t support the -opt switches, to keep things
simple.) From the Unix “nslookup man page(1M)”:
“nslookup is an interactive program to query ARPA Internet
domain name servers. The user can contact servers to request
information about a specific host, or print a list of hosts
in the domain.”
import java.net.*;
public class nslookup {
public static void main(String arg[]){
if (arg.length == 0) showUsage();
InetAddress[] names = null;
try{
names = InetAddress.getAllByName(arg[0]);
}
catch (UnknownHostException e){
System.err.println("Error: Unknown Host: " + arg[0]);
System.exit(1);
}
for (int i=0; i< names.length; i++)
System.out.println
("\nName: " + names[i].getHostName() +
"\nAddress: " + names[i].getHostAddress());
}//main
public static void showUsage(){
System.out.println
("Usage:\n\tnslookup <ip name>");
System.exit(0);
}//showUsage
}//nslookup
Sockets . . . and Threads
Sockets
-- The Basics: TCP
-- The Not-So-Basics
-- The Basics: UDP
Quick Notes on Threads
-- A Threaded Example
Sockets
A java.net.Socket provides an easy interface to a TCP connection.
Of the eight Socket constructors, there are generally four commonly used:
public Socket(InetAddress address, int port);
Creates a stream socket and connects it to the specified port number at the
specified IP address.
public Socket(InetAddress address, int port, InetAddress
localAddr, int localPort);
Creates a socket and connects it to the specified remote address on the
specified remote port.
public Socket(String host, int port);
Creates a stream socket and connects it to the specified port number on
the named host.
public Socket(String host, int port, InetAddress localAddr,
int localPort);
Creates a socket and connects it to the specified remote host on the
specified remote port.
Sockets
Additionally, there are several commonly used Socket methods:
public InputStream getInputStream();
Returns an input stream for this socket.
public OutputStream getOutputStream();
Returns an output stream for this socket.
The streams returned
from these accessors
rely on TCP’s error
correction and flow
control.
public void close();
Closes this socket.
public int getPort();
Returns the remote port to which this socket is connected.
public InetAddress getInetAddress();
Returns the address to which the socket is connected.
public int getLocalPort();
Returns the local port to which this socket is bound.
Sockets: Simple Usage
We can therefore create a simple Socket with:
Socket s = new Socket (“acme.gatech.edu”, 13);
We can obtain a Stream for receiving information with:
InputStream in = s.getInputStream();
We can obtain a stream for sending information with:
OutputStream out = s.getOutputStream();
Socket Options in Java
Often, it is necessary to change basic features in Sockets. Berkeleyderived sockets allow one to set various standard options
Some options are available only for ServerSockets (explained later).
Standard socket options available in Java include:
SO_LINGER
-- The “Socket Option Linger”; for when a close call catches
material still in the send buffer
SO_TIMEOUT
-- The “Socket Option Timeout”; determines how long a
connection may be idle before timeout.
TCP_NODELAY
-- The so-called “Nagle’s Algorithm” option; useful for WAN-based
applications where small packets are likely (rlogin, ssh, telnet, etc.), and
limited window sizes will lead to delay.
Socket Options in Java
public void setSoLinger(boolean on, int linger);
Enable/disable SO_LINGER with the specified linger
time in seconds.
public void setSoTimeout(int timeout);
Enable/disable SO_TIMEOUT with the specified timeout, in
milliseconds.
public void setTcpNoDelay(boolean on);
Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
public int getSoLinger();
Returns setting for SO_LINGER.
public int getSoTimeout();
Returns setting for SO_TIMEOUT.
public boolean getTcpNoDelay();
Tests if TCP_NODELAY is enabled.
public void setSendBufferSize(int size);
Sets the SO_SNDBUF option to the specified value for this
DatagramSocket.
TCP/UDP Connections Distinguished
The foregoing examples used TCP connections: session oriented
connections with a high degree of congestion control and error
correction.
The Socket abstraction hides the SocketImpl class, which provides
these services. To that extent, TCP is said to provide “reliable”
services.
unreliable but fast
Datagram
TCP
error
correction;
reliable
TCP
There may be circumstances where we don’t want the overhead
associated with reliability. UDP, user datagram protocol, allows us to use
so-called ‘unreliable’ networking services. UDP is a datagram-oriented
protocol, meaning there is no session.
A Day Time Client
From RFC 867 (J. Postel, 1983):
“One daytime service is defined as a connection based
application on TCP. A server listens for TCP
connections on TCP port 13. Once a connection is
established the current date and time is sent out the
connection as a ascii character string (and any data
received is thrown away). The service closes the
connection after sending the quote.”
Thus, we simply write a program to connect to a
server’s port 13, and output the message.
import java.net.*;
import java.io.*;
public class DayTimeClient {
public static final int iDAY_TIME_PORT = 13; // RFC 867
public static final int BUFF = 256;
public static void main (String arg[]) throws Exception {
if (arg.length == 0)
showUsage();
Socket sock = new Socket(arg[0], iDAY_TIME_PORT);
InputStream is = sock.getInputStream();
int i; byte[] b = new byte[BUFF];
while ( (i=is.read(b)) != -1)
System.out.println(new String(b, 0, i));
}
public static void showUsage(){
System.err.println
("Usage:\n\tjava DayTimeClient <IP Address>");
System.exit(0);
}//showUsage
}//class DayTimeClient
Reading and Writing From Sockets
Sockets in Java are full duplex--meaning that they can
both send and receive information.
A good example of this feature is an echo client. The
echo service listens to Port 7, and simply returns or
‘echoes back’ all information received from the client.
An echo client, therefore, has to be able to send and
receive over the same socket.
Let’s look at an echo client written by Sun. . . .
public class EchoClient {
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket("taranis", 7);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println ("Don't know about host: taranis.");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for "
+ "the connection to: taranis.");
System.exit(1);
}
Source: http://www.javasoft.com
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null) {
out.println(userInput);
System.out.println
("echo: " + in.readLine());
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}
}
Analysis and An Idea
COMMENTS:
The entire program is a single static method (This is fine for an example).
The program seems to repeat much of the code from our example.
In fact, at some level this resembles most IO stream handlers.
IDEA:
Let’s abstract out the common stream handling features, and make
a client that reads from/writes to a stream.
We can then use this client for a variety of purposes.
NOTION:
We should thread the class we create. The need for threading requires
more explanation.
ServerSockets
We may also wish to have a process listening on a port for incoming
calls. Perhaps we’ve written a web browser that stands ready to
send HTML content when a connection is made.
The ServerSocket class allows us to capture incoming calls.
ServerSocket outSock = new ServerSocket (6000);
while (true)
{
Socket inSock = outSock.accept();
handleConnection(inSock);
inSock.close();
}
ServerSockets
public ServerSocket(int port);
Creates a server socket on a specified port.
public ServerSocket(int port, int backlog);
Creates a server socket and binds it to the specified
local port number.
public ServerSocket
(int port, int backlog, InetAddress bindAddr);
Create a server with the specified port, listen backlog,
and local IP address to bind to.
public Socket accept();
Listens for a connection to be made to this socket and accepts it.
public void close();
Closes this socket.
public InetAddress getInetAddress();
Returns the local address of this server socket.
Blocking Network Calls
When using ServerSockets, be aware: the call to “accept()”
causes the program to wait until the method returns. This
“blocking call” can cause a program to hang.
ServerSocket servSock = new ServerSocket (6000);
while (true)
{
Socket inSock = servSock.accept();
handleConnection(inSock);
inSock.close();
}
If other operations must take place, we need some way of
placing the “accept()” call in its own thread.
Threads
Quickly, Incompletely Defined:
A Thread is a lightweight process (chunk of code) that can act
independently of another any other code in an application. They allow us
to give the illusion that more than one process is running at the same
time.
How-To in Java:
Subclass java.lang.Thread, or implement the interface Runnable
and provide a method:
public void run()
{
// threaded code goes here
}
The method run() is started via a call to “start()”. (One can also override
start(), but this is not always necessary.)
Simple Threads Example
public class Clock extends Thread {
String strSound;
public Clock(String strSound){
Note use of infinite loop
this.strSound = strSound;
in the run() method
}
public void run(){
while (true){
System.out.println (strSound);
try{ this.sleep(1000);}// DOES NOT BLOCK
catch (InterruptedException e){}
}
}
This code can run while other
threads are being run!
public static void main (String arg[]){
Clock c1 = new Clock("Tick");
Clock c2 = new Clock("Tock");
c1.start();
c2.start();
}
}// class Clock
Order of execution
between c1 and c2
is not guaranteed!
Thread Issues
Race Conditions:
Access to shared objects may result in race conditions. One
can guard against this mutexing or synchronizing blocks of code:
public synchronized void increaseAccount(){
// mutexed operations
}
Deadlocks:
Pervasive use of semaphores can, if improperly designed,
result in deadlock conditions.
Threaded Socket Clients
Using these principles, we can design a simple client that opens
a TCP socket, and has facilities for reading/writing to the socket.
SocketClient
Interface
SocketClientConstants
Interface
DefaultSocketClient
Class
The key is that the client class Threads itself--preventing it from
blocking other code.
Threaded Socket Clients: Interfaces
public interface SocketClientInterface
{
boolean openConnection();
void handleSession();
void closeSession();
}
public interface SocketClientConstants
{
int iECHO_PORT = 7;
int iDAYTIME_PORT = 13;
int iSMTP_PORT = 25;
boolean DEBUG = true;
}
import java.net.*;
import java.io.*;
public class
DefaultSocketClient
extends Thread implements SocketClientInterface,
SocketClientConstants {
private
private
private
private
private
BufferedReader reader;
BufferedWriter writer;
Socket sock;
String strHost;
int iPort;
public DefaultSocketClient(String strHost, int iPort) {
setPort (iPort);
setHost (strHost);
}//constructor
public void run(){
if (openConnection()){
handleSession();
closeSession();
}
}//run
public boolean openConnection(){
try {
sock = new Socket(strHost, iPort);
}
catch(IOException socketError){
if (DEBUG) System.err.println
("Unable to connect to " + strHost);
return false;
}
try {
reader = new BufferedReader
(new InputStreamReader(sock.getInputStream()));
writer = new BufferedWriter
(new OutputStreamWriter (sock.getOutputStream()));
}
catch (Exception e){
if (DEBUG) System.err.println
("Unable to obtain stream to/from " + strHost);
return false;
}
return true;
}
public void handleSession(){
String strInput = "";
if (DEBUG) System.out.println ("Handling session with "
+ strHost + ":" + iPort);
try {
while ( (strInput = reader.readLine()) != null)
handleInput (strInput);
}
catch (IOException e){
if (DEBUG) System.out.println ("Handling session with "
+ strHost + ":" + iPort);
}
}
public void sendOutput(String strOutput){
try {
writer.write(strOutput, 0, strOutput.length());
}
catch (IOException e){
if (DEBUG) System.out.println
("Error writing to " + strHost);
}
}
public void handleInput(String strInput){
System.out.println(strInput);
}
public void closeSession(){
try {
writer = null;
reader = null;
sock.close();
}
catch (IOException e){
if (DEBUG) System.err.println
("Error closing socket to " + strHost);
}
}
public void setHost(String strHost){
this.strHost = strHost;
}
public void setPort(int iPort){
this.iPort = iPort;
}
public static void main (String arg[]){
/* debug main; does daytime on local host */
String strLocalHost = "";
try{
strLocalHost =
InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e){
System.err.println ("Unable to find local host");
}
DefaultSocketClient d = new DefaultSocketClient
(strLocalHost, iDAYTIME_PORT);
d.start();
}
}// class DefaultSocketClient
Threaded Client Sockets
To use this threaded client, we merely subclass it, override the
handleConnection() method, and spawn off new instances.
DefaultSocketClient
start()
Networked
GUI
Our Specific
Socket Client
(e.g., web browser)
View (Buttons, etc.)
Sending Mail
We can use our Threaded Client to write a simple e-mail client.
We won’t implement the user interface beyond a debug test main.
(We could design a complex GUI, but won’t right now.)
DefaultSocketClient
MailSocket
-- Changes handleSession()
to match RFC mail requirements
QuickMail
(Sends a
test message)
Sending Mail
public class MailSocket extends DefaultSocketClient {
String strMessage;
String strRecipient;
String strSender;
public MailSocket(String strServer, String strSender,
String strRecipient, String strMessage){
super (strServer, iSMTP_PORT);
this.strMessage = strMessage;
this.strRecipient = strRecipient;
this.strSender = strSender;
}
/* cont’d
. . .
Note that we could also have more constructor variables-subject line, etc. etc.
*/
Sending Mail
public void handleSession(){
if (DEBUG)
System.out.println("Sending mail");
sendOutput("HELO fromQuickMail\n");
/* Some servers verify this!!*/
sendOutput("MAIL FROM: <" + strSender + ">\n");
sendOutput("RCPT TO: " + strRecipient + "\n");
sendOutput("DATA\n");
sendOutput("Subject: Here's some mail\n");
sendOutput("From: Your Name <" + strSender + " >\n");
sendOutput("\n\n");
/* send the message */
sendOutput(strMessage);
sendOutput("\n.\n\n");
sendOutput("QUIT\n");
if (DEBUG)
System.out.println("Sent mail");
}
}// class MailSocket
Sending Mail
public class QuickMail {
public static void main (String arg[]){
MailSocket mSock = new MailSocket
("mail.mindspring.com",
"david.dagon@mindspring.com",
"david.dagon@mindspring.com",
"Hi Dave,\n Here’s some mail from GSMAS.\n");
mSock.start();
}
} // class QuickMail
Note: I don’t mind getting e-mail from GSAMS participants;
you might want to use your own e-mail address when testing.
URLs
A URL specifies the location of networked resource--a file, for example.
A common URL is one for a web resource:
http://www.javasoft.com
Host Name -- the name of the machine
‘hosting’ the resource
Other protocols are possible:
Filename -- the pathname to the file on
the host
ftp://
file://
jdbc://
Port Number -- the port number to
which to connect (optional).
Reference -- a reference to a named
anchor within a resource that usually
identifies a specific location within a
file (optional).
URLs
The easiest way to create a URL in Java is to start with a String:
try{
URL myURL = new URL (“http://www.cc.gatech.edu”);
}
catch (MalformedURLException e){
System.err.println (“This method: “ + e.toString());
}
URLs can also be created relative to an existing URL:
try{
URL firstURL = new URL(“http://www.foo.com/top_level”);
URL secondURL =
new URL (firstURL, “lower_level”);
}
catch (Exception e){;}
Using URLs
URLs contain many useful methods, including:
getProtocol();
returns the protocol identifier component of the URL (ftp/http,
e.g.).
getHost();
returns the host name component of the URL.
getPort();
returns the port number component of the URL (or -1 if not set).
getFile();
returns the filename component of the URL.
getRef();
returns the reference component of the URL.
import java.net.*;
import java.io.*;
public class URLReaderExample {
public static void main
(String[] args) throws Exception {
if (args.length == 0) showUsage();
URL myURL = new URL("http://” + args[0]);
BufferedReader in =
new BufferedReader(new InputStreamReader
(myURL.openStream()));
String strInput;
while ((strInput = in.readLine()) != null)
System.out.println(strInput);
in.close();
}
public static void showUsage(){
System.err.println
("Usage:\n\tjava URLReaderExample <IP Address>");
System.exit(0);
}//showUsage
}//URLReaderExample
Connecting to a URL
One can also use “openConnection()” to connect to a URL. This
creates a communication link between your Java program and the
URL over the network. For example:
try {
URL myURL =
new URL("http://www.blarg.foo.org/");
myURL.openConnection();
}
catch (MalformedURLException e)
{
;
}
catch (IOException e)
{
;
}
One can then interact with the remote URL. (E.g., POST information
to web pages
Extracting the Stream from a URL
import
import
public
public
java.net.*;
java.io.*;
class URLConnectionReader {
static void main
(String[] args) throws Exception {
URL myURL =
new URL("http://www.cc.gatech.edu/");
URLConnection uc = myURL .openConnection();
BufferedReader in = new BufferedReader
(new InputStreamReader
(uc.getInputStream()));
/* see also getOutputStream() */
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
} }
RMI:
“Distributing the Object”
Being a Analysis of Java’s
Remote Method Invocation
Capabilities
1.
Motivation
CORBA & RMI:
Two Flavors of Alphabet Soup?
Maybe you’ve heard of CORBA and/or RMI:
the “new hot thing” in computing.
GUI
CORBA
HTML
OMG IDL
Thin Clients
(CGI)
URL
Java ORB
(UDP)
Foo
(TCP/IP)
Null Clients
HORB
(Non-type-safe
Interaction)
It’s hard to understand CORBA and RMI,
in part because of all the confusing terms...
What is CORBA?
DEFINED
The Common Object Request Broker
Architecture defines a model of
distributed computing.
PURPOSE
Allows local invocation of operations
on objects located anywhere on a
network.
What is RMI?
DEFINED
Java’s Remote Method Invocation
defines a model of distributed
computing.
PURPOSE
Allows local invocations of operations
on objects located anywhere on a
network.
What’s the Difference?
•
•
•
•
•
CORBA supports multiple languages
RMI is (relatively) easier to implement
RMI allows optimization of protocols for communication
CORBA separates interface definitions from implementation
HORB, a variant of RMI, actually works in JDK 1.02 (and
therefore in most browsers without error).
Here, we only add to the confusion with more terms.
It might help to see an example of RMI.
2.
“Hello RMI”
A Contrived Experiment With RMI
For this experiment, you will need:
Two Java-ready Computers
Two Fake Passports
Three round trip tickets to Moscow
3,500 Miles of CAT-5 wiring
John Doe
BOARDING PASS
An MI5 License to Thread
Experiment With RMI (Cont’d)
1.
Hook one end of
the CAT 5 cable to
a plane, and the
other end to the
first computer.
2.
Fly to Moscow.
3.
Blend in with the natives,
and connect the cable to
the second computer.
Experiment With RMI (Cont’d)
4.
Return home.
You now have
a network.*
RMI lets us invoke
methods that are found
on the remote machine.
So let’s write a little program . . .
*(You may use
a different
networking
configuration,
if you’re short
on cable.)
Program: Matryoshka Doll Server
We will use this network to smuggle Matroyska dolls into
the U.S.
Our Moscow server will take in a doll, and return a new
instance, encapsulating our original reference.
Stubs
DollClient
public
MatroyskaDoll
getDoll
(MatroyskaDoll d);
Moscovite
Implementation
DollServer
public
MatroyskaDoll
getDoll
(MatroyskaDoll d) {
// working code
}
RMI Design Cycle
Start
Client
Data
Types
policy
Define
Interface
Implement
Interface
javac
Implement
Client
Client Stub
CLIENT
Compile
javac
rmic
Bind
Objects
Start
Server
policy
Start
RMI Registry
Server
class
Server
skeleton
SERVER
1. Common Data Type
public class Matryoska
implements java.io.Serializable {
private Matryoska child;
private String strMicrofilm;
public Matryoska(String strMicrofilm,
Matryoska child){
setChild(child);
setMicrofilm(strMicrofilm);
This is merely
}
public void setMicrofilm (String strMicrofilm){
a linked list
this.strMicrofilm = strMicrofilm;
structure, but
}
it must support public void setChild(Matryoska child){
serialization
this.child = child;
}
public Matryoska getChild(){
return child;
}
public String getMicrofilm(){
return strMicrofilm;
}
}// class Matryoska
TOP SECRET:
2. Define The Interface
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface DollDesign extends Remote {
Matryoska getDoll(Matryoska doll)
throws RemoteException;
}
This means our
object is Callable
from any VM
Communication
failure or protocol
problem occurs
The java.rmi package:
java.rmi
java.rmi.activation
java.rmi.dgc
java.rmi.registry
java.rmi.server
3. Implement the Interface
Or extend
java.rmi.activation.
Activatable (JDK 1.2)
import java.rmi.*;
import java.rmi.server.*;
import java.net.*;
public class DollImplementation extends UnicastRemoteObject
implements DollDesign {
public DollImplementation() throws RemoteException {
super();
}
public Matryoska getDoll(Matryoska doll)
throws RemoteException {
return new Matryoska
(strMessage, doll);
}
public static String strMessage=”From Moscow With Stubs";
Causes
object to
be exported
Convenience class;
defines java.lang.Object
methods to work with
RMI (exports bytes, etc.)
calls UnicastRemoteObject.
exportObject()
3. Implement Interface (cont’d)
public static void main (String arg[]) {
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
try {
String name = "secretAgent"; /* or “//host/secretAgent” */
strMessage = InetAddress.getLocalHost().getHostName();
DollDesign secretAgent = new DollImplementation();
System.out.println ("Attempting to bind name:" + name);
Naming.rebind(name, secretAgent);
System.out.println ("Mission accomplished."
+ "\n\tOperative: " + name + "bound on " + strMessage);
}
catch (Exception e) {
System.err.println ("Nyet.");
System.err.println (e.getMessage());
Note the upcasting to
e.printStackTrace();
the interface from the
}
}//main
implementation; this
}//DollImplemenation
exposes the stubs
and not the object!
4. Compile (javac & rmic)
Bash
Bash
Bash
Bash
%
%
%
%
javac Matryoska.java
javac DollImplementation.java
rmic DollImplementation
ls -l
-rw-rw-r--rw-rw-r--rw-rw-r--rw-rw-r--rw-rw-r--rw-rw-r--rw-rw-r--rw-rw-r--
1
1
1
1
1
1
1
1
boris
boris
boris
boris
boris
boris
boris
boris
247
181
1757
1293
1729
3225
530
393
Apr
Apr
Apr
Apr
Apr
Apr
Apr
Apr
12
12
12
12
12
12
12
12
14:36
14:20
14:58
14:58
15:28
15:28
14:36
14:36
Bash%
Skel == Server
Stubs == Client
Rmic is an RMI
compiler for
java. It’s in the
soup.
DollDesign.class
DollDesign.java
DollImplementation.class
DollImplementation.java
DollImplementation_Skel.class
DollImplementation_Stub.class
Matryoska.class
Matryoska.java
6. From Moscow With Stubs
Note use
of debugging
listing of
available
objects
import java.rmi.*; import java.net.*;
public class DollClient{
public static void main (String arg[]) {
if (System.getSecurityManager()==null)
System.setSecurityManager
(new RMISecurityManager());
try {
String name = "//" + arg[0] + "/secretAgent";
String[] agents = Naming.list(name);
for (int i=0; i<agents.length; i++)
System.out.println
("\t-->" + agents[i] + " found");
String localHost = InetAddress.
getLocalHost().getHostName();
DollDesign secretAgent =
(DollDesign) Naming.lookup(name);
Matryoska doll = new Matryoska (localHost, null);
doll = secretAgent.getDoll(doll);
System.out.println ("Done”);
while (doll!=null){
System.out.println ("Doll-->"
+ doll.getMicrofilm());
doll=doll.getChild(); } }//try
6. From Moscow With Stubs (cont’d)
catch (Exception e){
System.err.println
("Error: " + e.getMessage());
e.printStackTrace();
}
}//Main
}//DollClient
NOTE:
NOTE:
NOTE:
We only create
an instance
of the interface,
not the remote
implementation
Client must
set a security
manager as
well; a similar
policy must be
invoked
Remote
resolution
of stubs
requires
use of security
manager
Smuggling Matryoska Dolls
grant {
permission java.net.SocketPermission
"*:1024-65535", “connect,accept";
permission java.net.SocketPermission
"*:80", "connect";
};
7.
OK. Fly
back to
Moscow
and make
a file
called
“java.policy”
Bash % rmiregistry &
[5] Pid 4523
Bash % unset CLASSPATH
Bash % java Djava.security.policy=java.policy
DollImplementation &
[6] Pid 4524
Set the policy
Bash %
file on startup
with the -D
option, or else!
8. Start The Client
Bash % java -Djava.security.policy=java.policy
DollClient
8.
Fly home
and create
a similar
policy file
for the
client.
Start the
service.
Failure to start
with the policy
option will throw
a security
exception. This
is new to JDK 1.2
3.
RMI Redux
RMI Summary: Value
RMI passes local objects by value--a copy gets
sent.
RMI passes remote objects by reference--not
by copying.
RMI stubs are proxies for the client to remote
object (just like CORBA).
RMI Summary: Errors & GC
Additional errors can be encountered; new
exceptions must be addressed.
RMI uses a reference counting gc; a zero count
marks the distributed object as a weak reference.
A “lease” is made on remote objects with a “dirty”
call. Leases must be renewed or will expire.
The java.rmi.server.Unreferenced interface
allows objects to receive notification just prior to
finalization. (Single method: unreferenced() ).
RMI Summary:
LocateRegistry
Default port: 1099
Class java.rmi.registry.LocateRegistry helps
locate remote registries:
public static Registry getRegistry(); /* local */
public static Registry getRegistry
(String host, int port);
public static Registry getRegistry
(String host);
public static Registry createRegistry (int port);
java.rmi.Naming Class
void bind(String name, Remote obj)
throws RemoteException,
AlreadyBoundException, AccessException;
Binds the specified name to a remote object.
String[] list()
throws RemoteException, AccessException;
Returns an array of the names bound in the registry.
Remote lookup(String name)
throws RemoteException,
NotBoundException, AccessException;
Returns a reference, a stub, for the remote object
associated with the specified name.
void rebind(String name, Remote obj)
AccessException;
throws RemoteException,
Rebinds the specified name to a new remote object.
void unbind(String name) throws
NotBoundException, AccessException;
RemoteException,
Destroys the binding for the specified name that is
associated with a remote object.
RMI: Dynamic Stub Loading
Dynamic stub loading is used where the client
does not have local copies of the remote object.
The stubs can even be generated on the fly.
Lookup:
1) Local resolution attempted via CLASSPATH
-- no security manager required
2) Server tells client the stub’s URL
java.rmi.server.codebase
-- can even be a third party Registry !
-- requires security manager
Java Native Invocation
“Return of the Native Method”
Native Methods--What?
• Through Java Native Interface (JNI), Java supports the
ability to call native methods--shared object files written in
languages such as C/C++
• The native keyword is used to identify methods that have
implementation defined in such shared object files:
public void native sayHello();
JNI
Java program
Share
Native
object
Native Methods -- Why?
• Before writing JNI, consider:
– Could the program be rewritten in/ported to Java?
– It’s possible to write programs quickly in Java
– What happens to portability?
• JNI provides a means of providing cross-platform
native code, but only if appropriate libraries are
generated for each machine. (Code is portable,
but not WORA--write once, run anywhere.)
JNI Generation--Overview
Java Source
with native
Shared Object
File (observe
naming conventions)
javac
Java Class File
(byte code)
Java Source
File loading
library
javah -jni
C/C++ Header
#include
JNI Implementation
(C/C++ Code)
Execution
Step 1: Organizing JNI vs. Java Functionality
First, decide what code belongs with native methods,
and what is better left to Java. Consider:
1) JNI means loss of visibility modifiers
(even private members can be discovered!)
2) JNI means manual garbage collection-difficult at times
3) JNI can imply a loss of OO control, unless
native implementation is in C++, or a very
OO-oriented set of C libraries.
public class HelloWorld
{
public native void sayHello(String strMessage);
public void speakUp()
{
System.out.println
("Java Says Hello, C");
sayHello("C Says Hello, Java");
}// speakUp()
}// class HelloWorld
Step 2: Generate Header File
1) Use javah tool from JDK to create header file.
2) Target your compiled class file.
3) Be sure to use the -jni switch:
%javah -jni HelloWorld
4) For older, non-JNI header files, use the -stub
option with javah. (Ask: why are you using the old
native invocation anyway? Consider upgrading to
1.1)
5) Don’t edit the source Java file (e.g., even
adding a package statements invalidates the
header file.)
This should create a header file essential
for your implementation . . .
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:
HelloWorld
* Method:
sayHello
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_HelloWorld_sayHello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
See the
“Do Not Edit”
Warning?
Obey!
Step 3: Implement Your JNI Method
1)
#include the header from javah
2)
Use the function prototypes generated by javah
3) Remember that Java Strings are objects, not char
arrays.
4) Consult the JNI API for a list of helpful
functions and methods
5) Note that ALL functions have two parameters, at
least:
JNIEnv * env, jobject thisObj
These are references to the VM and “this” object,
respectively. They are the window into the process
running in the VM.
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_sayHello
(JNIEnv * env, jobject thisObj, jstring strMessage){
const char *str =
(*env)->GetStringUTFChars(env, strMessage, 0);
printf("%s\n", str);
(*env)->ReleaseStringUTFChars(env, strMessage, str);
}// JNI method
/*Note need to convert chars from Unicode to UTF,
and then free created char buffer from the VM */
4. Compile the Object
Observe the naming convention:
lib<ShareObject>.so
LINUX:
%cc -I$JDK_HOME/include -I$JDK_HOME/include/genunix \
-shared -o libHello.so Hello.c
SOLARIS:
%cc
-I$JDK_HOME/include -I$JDK_HOME/include/solaris \
-G -o libHello.so Hello.c
WINDOWS:
Consider using a GNU port, or the upcoming batch file ...
ftp://go.cygnus.com/pub/ftp.cygnus.com/
gnu-win32/gnu-win32-b18/cdk.exe
#
# Makefile for Linux JNI Compilation
#
UPATH
= /usr/bin/
JDK_PATH
= /usr/local/jdk117_v1a/
# define utility programs and options
CC = $(UPATH)cc
CFLAGS = -I$(JDK_PATH)include -I$(JDK_PATH)include/genunix -shared
MAKE
= $(UPATH)make
CTAGS
= $(UPATH)ctags
For Solaris,
INDENT = $(UPATH)indent -bl -c41 -i4 -l72 -pcs
change to
# default target - builds Hello executable
#
/solaris
Hello: Hello.c
and -G
$(CC) $(CFLAGS) -o libHello.so Hello.c
# "debug" target - builds executable with debug code
#
debug: Hello.c
@CFLAGS="$(CFLAGS) -DDEBUG";export CFLAGS;$(MAKE) -e
# "pretty" target - beautify source files
pretty: Hello.c
ls $? | xargs -p -n1 $(INDENT)
@touch pretty
# "clean" target - remove unwanted object files and executables
clean:
rm -f Hello Hello.o pretty tags lint nohup.out a.out core
Windows Batch File
@echo Batch File for JNI W95 DevStudio 5
@echo Making clean
@del *.obj
@del *.lib
@del *.dll
@del *.pch
@del *.pdb
@del *.exp
@del *.idb
@echo Compiling all C files from this directory...
@cl -I%JDKPATH%\include -I%JDKPATH%\include\win32
/nologo /MTd /W4 /Gm /GX /Zi /Od /D "WIN32"
/D "_DEBUG" /D "_WINDOWS" /YX /c /LD *.c
@echo linking ...
@link /nologo /subsystem:windows /dll /incremental:no
/machine:I386 /out:%1.dll *.obj
5. Load the Library
public class Test{
static {
/*
* Our library is in a file called "libHello.so", but
* just pass in "Hello" since Java will prepend "lib"
* and append the ".so" extension. Windows users
* should omit the “.dll” extension as well.
*/
System.loadLibrary("Hello");
}// static load
public static void main (String arg[]) {
HelloWorld hw = new HelloWorld();
hw.speakUp();
} // main
}// class Test
6. Execute
1) Make sure the library is in the path of the
environment variable:
LD_LIBRARY_PATH
2)
For your shell, you can set:
LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
3) Windows users need to set the PATH
appropriately:
PATH=%PATH%;c:\MyLibrary
7. DEBUG (and repeat . . .)
Numerous problems may come up during compilation.
Resources for debugging JNI problems:
http://www.codeguru.com/java/JNI/index.shtml
http://www.mindspring.com/~david.dagon/jni/Native.txt
Concluding Thoughts
Thank you for your patience, and very constructive suggestions! I’ve
enjoyed working on this lecture series.
If you’re ever called upon to deliver a satellite lecture, may I offer some of
my experiences?
Lessons learned:
-- GSAMS lectures are a different beast.
-- Two-way connectivity is present, but needs to be facilitated.
-- Lecture materials need can develop contextual dependencies
that make them unsuitable/irrelevant for wider audiences.
-- Provide supplemental feedback mechanisms: the “television”
effect seems to limit some types of discussion, and encourage others.
-- The lecture ends when the network goes down.
Download