Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
COMPS311F Li Tak Sing Connectionless transmission The advantages of using connection-oriented transmission: reliable. The data will be retransmissed if it is lost. the order of the data is presvered. Disadvantage: there is overhead in creating a connection between two point. Therefore, if reliability is not the prime concern, we can use connectionless transmssion. For example, in transmiting audio signal, a packet lost will only affect the audio playing for a very short period of time. Connectionless transmission Advantage efficient. There is no need to establish a connection first before transmission. Disadvantages there may be data loss. The sender would not know the loss and therefore would not be able to resend it. The order of the data arriving at the destination is not garantteed to be the same as that when they are sent. Datagram DatagramSocket is the one in Java used in connectionless transmission. In connectionless transmission, there is no difference between a server and a client. Both use the same socket for reading and writing packets. The only difference is that the server must specify a port for the socket, but there is no need for the client to specify a port. The system will randomly assign a port for the client. However, a client can still specify a port if he/hse insists. DatagramPacket is used to carry the data between the sender and receiver. DatagramSocket Two commonly used constructors DatagramSocket(int port) This is mainly used in a server. DatagramSocket() This is mainly used in a client. Methods of DatagramSocket public void send(DatagramPacket p) throws IOException This method is used to send a packet to somewhere. The destination is specified in the DatagramPacket. Note that the sender would not know that the packet has reached the destination or not. public void receive(DatagramPacket p) throws IOException This method receives a packet from the socket. When the method returns, the buffer in the DatagramPacket is filled with data from the sender. The DatagramPacket would also contains the IP address, port number of the source so that we can send back a reply. Methods of DatagramSocket public void close() closes this datagram socket. Constructors of DatagramPacket public DatagramPacket(byte[] buf, int len) Constructs a DatagramPacket for receiving packets of length len. len must be less than or equal to buf.length. Note that the destination of the packet has not been specified. Usually, this is used for receiving a packet. public DatagramPacket(byte[] buf, int off, int len, InetAddress address, int port) Constructs a datagram packet for sending packets of length len with offset off to the specified port at the address. Usually this is for sending a packet. Methods of DatagramPacket public InetAddress getAddress() Returns the IP address of the machine to which this datagram is being sent or from which the datagram was received. public int getPort() Returns the port number on the remote host to which this datagram is being sent or from which the datagram was received. public byte[] getData() Returns the data buffer. The data received or the data to be sent starts from the offset in the buffer, and runs for length long. Methods of DatagramPacket public int getLength() Returns the length of the data to be sent or the length of the data received. public int getOffset() Returns the offset of the data to be sent or the offset of the data received. public void setAddress(InetAddress iaddr) Sets the IP address of the machine to which this datagram is being sent. public void setPort(int iport) Sets the port number on the remote host to which this datagram is being sent. Methods of DatagramPacket public void setData(byte[] buf) Set the data buffer for this packet. With the offset of this DatagramPacket set to 0, and the length set to the length of buf. In the server In a server: DatagramSocket socket=new DatagramSocket(12345); while (true) { byte b[]=new b[1000]; DatagramPacket p=new DatagramPacket(b,0,b.length); socket.receive(p); .... // do something about the client DatagramPacket rp=new DatagramPacket(c, off, len, p.getAddress(), p.getPort()); socket.send(rp); .... } To DatagramPacket Since DatagramPacket can only carry data in byte[], we need to convert all data types into byte[] before they can be sent to a DatagramPacket. This can be done by ByteArrayOutputStream: ByteArrayOutputStream out=new ByteArrayOutputStream(); DataOutputStream output=new DataOutputStream(out); output.writeInt(3); output.writeUTF("abc"); output.close(); byte[] b=out. toByteArray(); From DatagramPacket Similarly we need to use a ByteArrayInputStream to extract the data from a byte[]. DatagramPacket p=new DatagramPacket(b,b.length); socket.receive(p); DataInputStream input=new DataInputStream( new ByteArrayInputStream(p.getData(), p.getOffset(), p.getLength()); int i=input.readInt(); String st=input.readUTF(); .... In the client DatagramSocket socket=new DatagramSocket(); DatagramPacket p=new DatagramPacket(b,off,len, address, 12345); socket.send(p); ... DatagramPacket rp=new DatagramPacket(c,0,c.length); socket.receive(rp); A simple echo server The server would receive packets from any clients. The packets contain a string from the clients. The server would display the string on its window and return another packet that contains the string. The echo client The echo client allows the user to type in message and then it would be sent to the server after pressing a button. The server would send back the same message and it would be displayed in the client's window. EchoServer The echo server can be downloaded at: http://plbpc001.ouhk.edu.hk/~mt311f/examples/mt3112010 /src/datagram.tgz It is a JFrame which contains a textarea called text for the display of messages from clients. The main login of the program is an infinite loop that containuously read from the DatagramSocket. java.net.DatagramSocket ss = new java.net.DatagramSocket(12345); byte[] buf = new byte[2000]; while (true) { java.net.DatagramPacket p = new java.net.DatagramPacket(buf, buf.length); ss.receive(p); java.io.DataInputStream input = new java.io.DataInputStream( new java.io.ByteArrayInputStream(p.getData(), p.getOffset(), p.getLength())); java.net.InetAddress address = p.getAddress(); int port = p.getPort(); String st = input.readUTF(); input.close(); text.append(address + ":" + port + ":" + st + "\n"); java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); java.io.DataOutputStream output = new java.io.DataOutputStream(out); output.writeUTF("echo:" + st); output.close(); byte rb[] = out.toByteArray(); java.net.DatagramPacket rp = new java.net.DatagramPacket(rb, 0, rb.length, address, port); ss.send(rp); The client public void actionPerformed(ActionEvent e) { try { java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); java.io.DataOutputStream output = new java.io.DataOutputStream(out); output.writeUTF(textfield.getText()); textfield.setText(""); output.close(); byte[] b = out.toByteArray(); java.net.DatagramPacket p = new java.net.DatagramPacket(b, 0, b.length, home, 12345); socket.send(p); byte[] b2 = new byte[2000]; java.net.DatagramPacket rp = newjava.net.DatagramPacket(b2, b2.length); socket.receive(rp); java.io.DataInputStream input = new java.io.DataInputStream(new java.io.ByteArrayInputStream(rp.getData(), rp.getOffset(), rp.getLength())); String st = input.readUTF(); text.append(rp.getAddress() + ":" + rp.getPort() + ":" + st + "\n"); } catch (Exception ee) { ee.printStackTrace(); } } A Multithreaded server The echo server we just showed is a single threaded server. This means that it can only serve one client at a time. If a packet comes when the server is busy serving another packet, then the former one will be dropped. The sender of this packet would not know that the packet has been dropped. To make a more reliable server, we can use a multithreaded server. A Multithreaded server In a server: DatagramSocket socket=new DatagramSocket(12345); while (true) { byte b[]=new b[1000]; DatagramPacket p=new DatagramPacket(b,0,b.length); socket.receive(p); new MyThread(p).start(); //MyThread is a thread which //will handle the packet. } MultithreadedEchoServer An inner class MyThread is defined in the server. private class MyThread extends Thread { private java.net.DatagramPacket packet; public MyThread(java.net.DatagramPacket packet) { this.packet = packet; } public void run() { try { java.io.DataInputStream input = new java.io.DataInputStream(new java.io.ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength())); java.net.InetAddress address = packet.getAddress(); int port = packet.getPort(); String st = input.readUTF(); input.close(); text.append(address + ":" + port + ":" + st + "\n"); java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); java.io.DataOutputStream output = new java.io.DataOutputStream(out); output.writeUTF("echo:" + st); output.close(); byte[] rb = out.toByteArray(); java.net.DatagramPacket rp = new java.net.DatagramPacket(rb, 0, rb.length, address, port); ss.send(rp); } catch (IOException ex) { Logger.getLogger(MultithreadedEchoServer.class.getName()).log(Level.SE VERE, null, ex); } } } Remote Method Invocation(RMI) For distributed computing. A Java object on one system can invoke a method in an object on another system on the network. It is build on top of sockets. Users there do not have to handle the sockets anymore. Communication between different computers can be done by invoking methods on a remote computers. How Does RMI work? Normal objects are called local objects. Objects that can be accessibled by RMI are called remote objects. For an object to be accessible remotely, there must be an interface defined in both server and client. The client would only use the interface to access the methods. The interface must be extended from java.rmi.Remote. Key components of RMI ■ Server object interface: A subinterface of java.rmi.Remote that defines the methods for the server object. ■ Server class: A class that implements the remote object interface. ■ Server object: An instance of the server class. ■ RMI registry: A utility that registers remote objects and provides naming services for locating objects. Key components of RMI ■ Client program: A program that invokes the methods in the remote server object. ■ Server stub: An object that resides on the client host and serves as a surrogate for the remote server object. ■ Server skeleton: An object that resides on the server host and communicates with the stub and the actual server object. Operations of RMI Operations of RMI 1. A server object is registered with the RMI registry. 2. A client looks through the RMI registry for the remote object. 3. Once the remote object is located, its stub is returned in the client. 4. The remote object can be used in the same way as a local object. Communication between the client and the server is handled through the stub and the skeleton. Passing Parameters ■ Primitive data types, such as char, int, double, or boolean, are passed by value like a local call. ■ Local object types, such as java.lang.String, are also passed by value, but this is completely different from passing an object parameter in a local call. In a local call, an object parameter’s reference is passed, which corresponds to the memory address of the object. In a remote call, there is no way to pass the object reference, because the address on one machine is meaningless to a different JVM. Any object can be used as a parameter in a remote call as long as it is serializable. The stub serializes the object parameter and sends it in a stream across the network. The skeleton deserializes the stream into an object. Passing Parameters ■ Remote object types are passed differently from local objects. When a client invokes a remote method with a parameter of a remote object type, the stub of the remote object is passed. The server receives the stub and manipulates the parameter through it. RMI Registry java.rmi.registry.LocateRegistry has the following static methods: public Registry getRegistry(): get the local registry at default port of 1099. public Registry getRegistry(int port): get the local registry at the specified port. public getRegistry(String host): get the remote registry at default port of 1099 on a remote computer. public getRegistry(String host, int port): get the remote registry at the specified port on a remote computer. Methods of java.rmi.registry.Registry void rebind(String name, Remote obj): bind the specified name to the remote object. void unbind(String name): unbind the name. Remote lookup(String name): return a reference of a remote object in the registry. Developing RMI Applications 1. Define a server object interface that serves as the contract between the server and its clients, as shown in the following outline: public interface ServerInterface extends Remote{ public void service1(...) throws RemoteException; // Other methods } A server object interface must extend the java.rmi.Remote interface. Developing RMI Applications 2. Define a class that implements the server object interface, as shown in the following outline: public class ServerInterfaceImpl extends UnicastRemoteObject implements ServerInterface { public void service1(...) throws RemoteException { // Implement it } // Implement other methods } Developing RMI Applications 3. Create a server object from the server implementation class and register it with an RMI registry: ServerInterface server = new ServerInterfaceImpl(...); Registry registry = LocateRegistry.getRegistry(); registry.rebind("RemoteObjectName", obj); Before running this program, start the RMI registry by running the command rmiregistry at a location where you can find the classes for the server. This can be done by setting appropriate class path or run the command at a suitable location. Developing RMI Applications 4. Develop a client that locates a remote object and invokes its methods, as shown in the following outline: Registry registry = LocateRegistry.getRegistry(host); ServerInterface server = (ServerInterfaceImpl) registry.lookup("RemoteObjectName"); server.service1(...); A simple RMI server that adds two integers. You can download the code at: http://plbpc001.ouhk.edu.hk/~mt311f/examples/mt311201 0/src/rmi.tgz The server has just one method: public int sum(int i,int j) The method would return the sum of i and j. RMIAddServer public interface RMIAddServer extends Remote { public int sum(int i, int j) throws RemoteException; //this method will return the sum of the two integers. } RMIAddServerImp public class RMIAddServerImp extends UnicastRemoteObject implements RMIAddServer { public RMIAddServerImp() throws RemoteException { } public int sum(int i, int j) throws RemoteException { return i+j; } RMIAddServerImp public static void main(String st[]) throws RemoteException { RMIAddServerImp obj=new RMIAddServerImp(); Registry registry= LocateRegistry.getRegistry(); registry.rebind("add", obj); } } ADDClient public class AddClient { public static void main(String st[]) throws RemoteException, NotBoundException { Registry registry=LocateRegistry.getRegistry("localhost"); RMIAddServer server=(RMIAddServer)registry.lookup("add"); System.out.println("The sum of 3 and 4 is "+server.sum(3, 4)); } } Start the server execute rmiregistry at a place where RMIAddServerImp.class can be found. Note that if we have use a package for RMIAddServerImp, then we should run rmiregistry at the parent directory of the package. RMI vs. Socket-Level Programming RMI enables you to program at a higher level of abstraction. You do not need to open, close a socket. RMI server is already multithreaded. So you do not have to worry about multithreading.