Mehrprozessorsysteme ohne gemeinsamen Hauptspeicher benötigen spezielle Leitungen zur Kommunikation.
Das Schema des Nachrichtenaustauschs ist in Abbildung 2 dargestellt.
Spezifikation von ServerSocket:
public ServerSocket(int port) throws IOException public Socket accept() throws IOException
Spezifikationen von Socket
public Socket(String host, int port) throws UnknownHostException, IOException public InputStream getInputStream() throws IOException public OutputStream getOutputStream() throws IOException
Zuordnung von passenden Datenströmen:
Spezifikation der benötigten Konstruktoren und Methoden
public ObjectOutputStream(OutputStream out) throws IOException public void flush() throws IOException public ObjectInputStream(InputStream in) throws IOException, StreamCorruptedException
Datenübertragung mit Send-Operation ( send) und Empfangs-Operation ( recieve).
Spezifikation aus ObjectOutputStream
public final void writeObject(Object obj) throws IOException
Spezifikation aus ObjectInputStream
public final Object readObject() throws OptionalDataException, ClassNotFoundException, IOException
Der Konstruktor nimmt einen Socket als Eingabe und setzt die Objekt-Ströme aus den entsprechenden Strömen auf.
Die Methode close() dient zum schließen des Kanals.
send()- und receive()-Methoden dienen der Datenübertragung
public class ObjectChannel { ObjectOutputStream out; ObjectInputStream in; public ObjectChannel(Socket s) throws IOException { out = new ObjectOutputStream( s.getOutputStream() ); in = new ObjectInputStream( s.getInputStream() ); } public void close() { try { out.close(); in.close(); } catch(IOException e) { e.printStackTrace(); } } public void send(Object o) throws IOException { synchronized(out) { out.writeObject(o); } } public Object receive() throws IOException, ClassNotFoundException { Object o = null; synchronized(in) { o = in.readObject(); } return o; } }
Die Sende- und Empfangs-Methoden sind wie folgt.
public void send(Object v) throws IOException { out.writeObject(v); }Im Fehlerfall wird eine IOException ausgelöst, die dann vom Aufrufer behandelt werden muß.
public Object receive() throws IOException, ClassNotFoundException { return in.readObject(); }Neben einer IOException kann auch noch eine ClassNotFoundException ausgelöst werden, falls das Objekt zu einer dem Empfänger unbekannten Klasse gehört.
Implementierung: HelloWorldClient.java HelloWorldServ.java SocketChannel.java ObjectChannel.java
Zwei Grundideen zur Lösung
Der Konstruktor der Klasse ChannelFactory erzeugt einen Server-Socket und startet sich dann selbst als Thread.
import java.io.*; import java.net.*; public class ChannelFactory extends Thread { public final static int DEFAULT_PORT = 4711; private int port; private BoundedBuffer buf = new BoundedBuffer(10); private ServerSocket srv = null; public ChannelFactory(int p) { if (p<=0) { port = DEFAULT_PORT; } else { port = p; } try { srv = new ServerSocket(port); this.start(); System.out.println( "server started on port "+port); } catch (IOException e) { System.out.println(e); } } public ChannelFactory() { this(DEFAULT_PORT); }
public void run() { while (true) { try { System.out.println( "waiting for connection"); Socket s = srv.accept(); System.out.println("connection accepted"); ObjectChannel c = new ObjectChannel(s); buf.put( (Object) c ); } catch (IOException e) { System.out.println(e); } } } public ObjectChannel getChannel() throws IOException { return (ObjectChannel)buf.get(); }
public ObjectChannel getChannel(String h, int p) throws IOException { if (p<=0) { p = port; } ObjectChannel c = null; System.out.println("connecting to "+h); while (c == null) { try { c = new ObjectChannel( new Socket(h, p) ); } catch (IOException e) { System.out.println(e); // wait server ready System.out.println("Server on "+h+ " not ready"); try { Thread.currentThread().sleep( (int)(5000)); } catch (InterruptedException e1) { } } } System.out.println("connected"); return c; } }
ChannelFactory löst das Reihenfolge-Problem und das Deadlock-Problem.
Das Reihenfolge-Problem wird durch Warten und Neuversuch in der Methode getChannel(String h, int p) gelöst.
Die Lösung des Deadlock-Problems wie folgt.
Wir setzen voraus, daß für jeden Prozeß genau einmal der Konstruktor ChannelFactory() und für jeden Kanal genau einmal die Methode getChannel() und die Methode getChannel(String h, int p) aufgerufen wird.
Betrachten wir die drei Programmzustände:Aufruf der Konstruktoren ChannelFactory(). Damit wird ein Thread gestartet, der Verbindungsanfragen vom Server-Socket entgegennimmt und speichert.
Aufruf von getChannel(String h, int p) auf allen Client-Seiten der Kanäle. Dabei wird die Verbindung zu Sockets aus Punkt 1 hergestellt. Falls diese noch nicht bereit sind, wird gewartet.
Aufruf von allen getChannel() auf den Server-Seiten der Kanäle. Dabei werden nur noch die gespeicherten Verbindungen zurückgegeben. Falls noch keine gespeichert sind, wird gewartet.
Kompliziertere Verbindungsstrukturen mit virtuellen Kanälen oder PVM oder MPI.
Implementierung: HelloWorldClientCF.java HelloWorldServCF.java ChannelFactory.java
© Universität Mannheim, Rechenzentrum, 2000-2016.
Last modified: Mon Jan 20 23:53:47 CET 2016