/* ** This file is part of Filius, a network construction and simulation software. ** ** Originally created at the University of Siegen, Institute "Didactics of ** Informatics and E-Learning" by a students' project group: ** members (2006-2007): ** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding, ** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer ** supervisors: ** Stefan Freischlad (maintainer until 2009), Peer Stechert ** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de> ** and Stefan Freischlad ** Filius is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) version 3. ** ** Filius is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ** PURPOSE. See the GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Filius. If not, see <http://www.gnu.org/licenses/>. */ package filius.software.clientserver; import filius.Main; import filius.rahmenprogramm.I18n; import filius.software.transportschicht.TCPSocket; /** * <p> * In dieser Klasse wird das Client-Programm einer einfachen * Client-Server-Anwendung implementiert. Nachrichten an die graphische * Benutzungsoberflaeche werden durch den Aufruf * banachrichtigeBeobachter(Object) versendet. * </p> * <p> * Aufrufe folgender Methoden des Sockets blockieren: * </p> * <ul> * <li> verbinden() </li> * <li> senden() </li> * <li> empfangen() </li> * <li> schliessen() </li> * </ul> * <p> * Deshalb muessen Methoden dieser Klasse, die Aufrufe dieser Methoden * enthalten, ueber die Methode <code>ausfuehren(String, Object[])</code> * aufgerufen werden. Das bewirkt, dass diese Methoden in einem eigenen Thread * ausgefuehrt werden und damit der aufrufende Thread nicht blockiert. Das ist * wichtig, wenn die Aufrufe von der graphischen Benutzungsoberflaeche * ausgeloest werden. * </p> * <p> * Ein Beispiel fuer die Verwendung von <code>ausfuehren()</code> ist * folgendes: <br /> * <code> public void verbinden(String zielAdresse, Integer port) { <br /> *    Object[] args; <br /> <br /> *    args = new Object[2]; <br /> *    args[0] = zielAdresse; <br /> *    args[1] = port; <br /> <br /> *    ausfuehren("initialisiereSocket", args); <br /> * } </p> * <p> Dabei wird als erstes Argument der auszufuehrenden blockierenden * Methode uebergeben (hier: <code> initialisiereSocket</code>) und dann in * einem Array die zu uebergebenden Parameter (hier: <code>zielAdresse</code> * und <code>port</code>). Der Aufruf der Methode <code>verbinden(zielAdresse, port) * </code> bewirkt also das Ausfuehren der Methode * <code>initialisiereSocket(zielAdresse, port)</code> in einem anderen Thread. * Damit blockiert die Methode <code>verbinden</code> nicht. </p> * <p> <b> Achtung:</b> Die indirekt aufgerufene Methode (d. h. ueber <code> * ausfuehren(String, Object[])</code>) muss als <code>public</code> deklariert * sein! </p> */ public class ClientBaustein extends ClientAnwendung implements I18n { /** Port-Nummer des Servers, an dem Verbindungsanfragen angenommen werden */ private int zielPort = 55555; /** * Adresse des Rechners, auf dem der Server laeuft als Domainname oder * IP-Adresse. */ private String zielIPAdresse; /** Methode zum Verbindungsaufbau zu einem Server. Hier wird der * Client-Socket als TCP/IP-Socket erzeugt. Wenn UDP verwendet werden soll, * muss diese Methode ueberschrieben werden. <br /> * Diese Methode ist <b>nicht blockierend</b>. Diese Methode veranlasst den * Aufruf von <code>initialisiereSocket</code> in einem anderen Thread. */ public void verbinden() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), verbinden()"); Object[] args; args = new Object[2]; args[0] = zielIPAdresse; args[1] = new Integer(zielPort); ausfuehren("initialisiereSocket", args); ausfuehren("empfangeNachricht", null); } /** Methode zum Verbindungsaufbau zu einem Server. Hier wird der * Client-Socket als TCP/IP-Socket erzeugt. Wenn UDP verwendet werden soll, * muss diese Methode ueberschrieben werden. <br /> * Diese Methode ist <b>nicht blockierend</b>. Diese Methode veranlasst den * Aufruf von <code>initialisiereSocket</code> in einem anderen Thread. * * @param zielAdresse * @param port */ /*private void verbinden(String zielAdresse, Integer port) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), verbinden("+zielAdresse+","+port+")"); Object[] args; args = new Object[2]; args[0] = zielAdresse; args[1] = port; ausfuehren("initialisiereSocket", args); }*/ /** * Nicht-blockierende Methode zum Versenden einer Nachricht an den Server. * Diese Methode veranlasst den Aufruf von <code>versendeNachricht</code> * in einem anderen Thread. * * @param nachricht * die zu versendende Nachricht */ /*public void senden(String nachricht) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), senden("+nachricht+")"); Object[] args; args = new Object[1]; args[0] = nachricht; ausfuehren("versendeNachricht", args); }*/ /*public void empfangen() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), empfangen()"); ausfuehren("empfangeNachricht", null); }*/ /** * Methode zum Aufbau einer Verbindung mit einem TCP-Socket. Diese Methode * ist blockierend und sollte nicht direkt von der GUI aufgerufen werden. */ public void initialisiereSocket(String zielAdresse, Integer port) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), initialisiereSocket("+zielAdresse+","+port+")"); try { socket = new TCPSocket(getSystemSoftware(), zielAdresse, port); socket.verbinden(); benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg2")); } catch (Exception e) { e.printStackTrace(Main.debug); socket = null; benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg1") + e.getMessage()); } } /** * Methode zum trennen einer Verbindung. Der Socket wird durch den Aufruf * der Methode schliessen() geschlossen und und der Socket fuer diese * Anwendung auf null gesetzt. <br /> * Diese Methode ist <b> blockierend</b>. */ public void trennen() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), trennen()"); if (socket != null) { socket.schliessen(); socket = null; benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg3")); } } /** * Diese Methode ist <b>blockierend</b> und sollte nicht direkt von der GUI * aufgerufen werden. */ /*public void schliesseSocket() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), schliesseSocket()"); if (socket != null) { socket.schliessen(); socket = null; benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg3")); } }*/ /** * Diese Methode ist <b>blockierend</b> und sollte nicht direkt von der GUI * aufgerufen werden. */ public void senden(String nachricht) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), versendeNachricht("+nachricht+")"); if (socket != null && socket.istVerbunden()) { try { socket.senden(nachricht); benachrichtigeBeobachter("<<" + nachricht); } catch (Exception e) { benachrichtigeBeobachter(e.getMessage()); e.printStackTrace(Main.debug); } } else { benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg4")); } } /** * Methode zum Empfang einer Nachricht vom Socket. Die empfangene Nachricht * wird mit <code>benachrichtigeBeobachter</code> an die GUI weiter * gegeben. Diese Methode ist blockierend und sollte nicht direkt von der * GUI aufgerufen werden. */ public void empfangeNachricht() { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ClientBaustein), empfangeNachricht()"); String nachricht; if (socket != null && socket.istVerbunden()) { try { while (this.istVerbunden()) { nachricht = socket.empfangen(); if (nachricht != null) { benachrichtigeBeobachter(">>" + nachricht); } else { benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg5") + " " + socket.holeZielIPAdresse() + ":" + socket.holeZielPort() + " " + messages.getString("sw_clientbaustein_msg6")); socket.schliessen(); } } } catch (Exception e) { benachrichtigeBeobachter(e.getMessage()); e.printStackTrace(Main.debug); } } else { benachrichtigeBeobachter(messages.getString("sw_clientbaustein_msg4")); } } /** Methode fuer den Zugriff auf die Server-Adresse */ public String getZielIPAdresse() { return zielIPAdresse; } /** Methode fuer den Zugriff auf die Server-Adresse */ public void setZielIPAdresse(String zielIPAdresse) { this.zielIPAdresse = zielIPAdresse; } /** * Methode fuer den Zugriff auf die Port-Nummer, an dem der Server zu * erreichen ist. */ public int getZielPort() { return zielPort; } /** * Methode fuer den Zugriff auf die Port-Nummer, an dem der Server zu * erreichen ist. */ public void setZielPort(int zielPort) { this.zielPort = zielPort; } }