From 8ea1060c44a91d5e38c038e07504dbe47811ff58 Mon Sep 17 00:00:00 2001 From: eichehome Date: Sun, 16 May 2021 20:03:38 +0200 Subject: [PATCH] =?UTF-8?q?Letzte=20Kommentare=20hinzugef=C3=BCgt,=20Namen?= =?UTF-8?q?=20geupdatet=20und=20Dateien=20formatiert.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/Client.java | 429 +++++++++----- src/client/Client1.java | 553 +++++++++--------- src/server/ClientReciveMessageThread.java | 52 +- ...read.java => ClientSendMessageThread.java} | 69 ++- src/server/ClientStore.java | 71 ++- src/server/MainServer.java | 15 +- src/utils/Client.java | 44 +- 7 files changed, 703 insertions(+), 530 deletions(-) rename src/server/{ClientPushMessageThread.java => ClientSendMessageThread.java} (55%) diff --git a/src/client/Client.java b/src/client/Client.java index 9881cb6..bfce9ee 100644 --- a/src/client/Client.java +++ b/src/client/Client.java @@ -1,15 +1,10 @@ package client; -import java.awt.BorderLayout; import java.awt.EventQueue; -import java.awt.TextArea; - import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; - import utils.Message; - import javax.swing.JTextField; import javax.swing.JButton; import javax.swing.JTextArea; @@ -19,159 +14,299 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; +import java.net.SocketException; import java.util.Scanner; import java.awt.event.ActionEvent; -public class Client extends JFrame { +/** + * Hauptklasse des Clients + * + * @version 0.1.3 + * @author berdan + */ +public class Client1 extends JFrame { + + /* + Hier werden Objekte und Variablen deklariert, damit diese + in allen Methoden genutzt werden können. + */ + private static JPanel contentPane; + JTextField txtMessage; + private static JTextField txtUsername; + public static String currentText = " "; + public static int i = 0; + public static Object tosend = new Message("Leer", "Leer"); + public static Client1 t1; + public static Socket socket; + public static ObjectInputStream obinstr; + public static ObjectOutputStream oboust; + public static boolean verbunden = false; + public static JTextArea textArea = new JTextArea(); + public static int anzahlVersuche = 0; //Ist gleich die AN + public static int anzahlRekursionen = 0; + public static Message temp = new Message("leer", "leer"); + + /* + In der main Methode wird das GUI erstellt und die + start() Methode aufgerufen. + */ + public static void main(String[] args) throws InterruptedException { + t1 = new Client1(); + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Client1 frame = new Client1(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + try { + start(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /* + In der Methode Client1() wird das GUI + und die Befehle die durch einen Click des + Button's ausgelöst werden festgelegt + */ + public Client1() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 450, 300); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(null); + + txtMessage = new JTextField(); + txtMessage.setText("Message"); + txtMessage.setBounds(20, 230, 218, 20); + contentPane.add(txtMessage); + txtMessage.setColumns(10); + + txtUsername = new JTextField(); + txtUsername.setText("Username"); + txtUsername.setBounds(20, 11, 86, 20); + contentPane.add(txtUsername); + txtUsername.setColumns(10); - private static JPanel contentPane; - JTextField txtMessage; - private JTextField txtUsername; - public static String currentText = " "; - public static int i = 0; - public static Object tosend = new Message("Leer", "Leer"); - public static Client t1; - public static Socket socket; - public static ObjectInputStream obinstr; - public static ObjectOutputStream oboust; - /** - * Beta Version des Clients - * @version 0.0.2 - * @author berdan + * Der Button "Send" nimmt die aktuelle Nachricht, welche im Textfeld + * "message" geschrieben wurde und schreibt diese als ein Message-Objekt + * in den Output-Stream an den Server, falls die Socket bereits + * verbunden ist. + * + * Falls die Nachricht "exit" sein sollte, wird die GUI beendet. */ - - + JButton btnSend = new JButton("Send"); + btnSend.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { - public static void main(String[] args) { - t1 = new Client(); - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - Client frame = new Client(); - frame.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - - - try { - start(); - } catch (ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + if (verbunden) { + String themessage = txtMessage.getText(); + String theusername = txtUsername.getText(); - public Client() { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(100, 100, 450, 300); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - setContentPane(contentPane); - contentPane.setLayout(null); - - txtMessage = new JTextField(); - txtMessage.setText("Message"); - txtMessage.setBounds(117, 29, 218, 20); - contentPane.add(txtMessage); - txtMessage.setColumns(10); - - txtUsername = new JTextField(); - txtUsername.setText("Username"); - txtUsername.setBounds(21, 29, 86, 20); - contentPane.add(txtUsername); - txtUsername.setColumns(10); - - JButton btnSend = new JButton("Send"); - btnSend.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - - String themessage = txtMessage.getText(); - String theusername = txtUsername.getText(); - - tosend = new Message(theusername, themessage); - i = 1; - - System.out.println("Button pressed"); - - try { - oboust.writeObject(tosend); - oboust.flush(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + tosend = new Message(theusername, themessage); + i = 1; - } - }); - - btnSend.setBounds(345, 28, 79, 23); - contentPane.add(btnSend); - - JTextArea textArea = new JTextArea(currentText); - textArea.setLineWrap(true); - textArea.setForeground(Color.WHITE); - textArea.setBackground(Color.LIGHT_GRAY); - textArea.setBounds(20, 60, 323, 176); - contentPane.add(textArea); - } - - public static void print(JTextArea textArea, String asd){ - currentText = asd + "\n" + currentText; - textArea.setText(currentText); - } - - public static void start() throws IOException, ClassNotFoundException{ - Scanner scan = new Scanner(System.in); - - JTextArea textArea = new JTextArea(currentText); - textArea.setLineWrap(true); - textArea.setForeground(Color.WHITE); - textArea.setBackground(Color.BLACK); - textArea.setBounds(20, 60, 323, 176); - contentPane.add(textArea); + temp = new Message(theusername, themessage); + System.out.println("Button pressed"); - socket = new Socket( "localhost", 1236 ); - oboust = new ObjectOutputStream(socket.getOutputStream()); - obinstr = new ObjectInputStream(socket.getInputStream()); - - Object erhalten = null; - Message message = new Message("leer", "leer"); - - while(!message.getMessage().equals("exit")){ - System.out.println("While"); - try{ - erhalten = obinstr.readObject(); //Bleibt hier stehen, bis ein neues Object reinkommt - System.out.println("Nachricht erhalten"); - message = (Message)erhalten; - System.out.println(message.getMessage()); - String Ausgeben = "[" + message.getUsername() + "] " + message.getMessage(); - print(textArea, Ausgeben); - System.out.println("[" + message.getUsername() + "] " + message.getMessage()); - oboust.flush(); - }catch(Exception f){ - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } - oboust.close(); - obinstr.close(); - socket.close(); - } - - + try { + try { + oboust.writeObject(tosend); + oboust.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (Exception k) { + print("KEINE VERBINDUNG"); + } - + if (temp.getMessage().equals("exit")) { + System.exit(0); + } + + txtMessage.setText(""); + + } + + } + }); + + btnSend.setBounds(264, 229, 79, 23); + contentPane.add(btnSend); + + /** + * Hier wird die textArea, auf welcher der Text ausgegeben wird + * initialisiert + * + */ + textArea = new JTextArea(currentText); + textArea.setLineWrap(true); + textArea.setForeground(Color.BLACK); + textArea.setBackground(Color.LIGHT_GRAY); + textArea.setBounds(20, 42, 323, 176); + contentPane.add(textArea); + + /** + * Der Start Button sorgt sorgt dafür, dass der Username festgesetzt + * wird, wodurch er nicht veränderlich ist. Außerdem wird die globale + * Variabel j von 0 auf 1 gestzt, wodurch die start-Methode weiß, dass + * sie eine Verbindung aufbauen soll. + * + */ + JButton btnStart = new JButton("Start"); + btnStart.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + + txtUsername.setEditable(false); + txtUsername.setEnabled(false); + verbunden = true; + + } + }); + btnStart.setBounds(116, 10, 89, 23); + contentPane.add(btnStart); + + } + + /** + * In der Print-Methode wird der neue Text (also eine neue Nachricht) auf + * die textArea abgebildet. + */ + public static void print(String neuerText) { + currentText = neuerText + "\n" + currentText; + + textArea.setText(currentText); + } + + /** + * Die start-Methode wartet, bis die Variable verbunden durch Klicken des + * Start Buttons auf true gesetzt wird, erst dann beginnt die eigentliche + * Methode. + * + * Es wird dann eine Verbindung zum Socket über den Port 1236 aufgebaut. + * Sollte dies nicht Möglich sein, wird die Fehlermeldung in der GUI + * ausgegeben, sodass der Nutzer weiß, dass keine Vebrindung möglich ist. + * + * Es wird im Sekundentakt nach einer neuen Verbindung gesucht. + * + */ + public static void start() throws IOException, ClassNotFoundException, InterruptedException { + + while (!verbunden) { + Thread.sleep(100); + } + + txtUsername.setEnabled(false); + Scanner scan = new Scanner(System.in); + + try { + socket = new Socket("localhost", 1236); + oboust = new ObjectOutputStream(socket.getOutputStream()); + obinstr = new ObjectInputStream(socket.getInputStream()); + print("VERBINDUNG HERGESTELLT"); + } catch (Exception KeineSocket) { + print("SERVER ANTWORTET NICHT"); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + anzahlRekursionen++; + if (anzahlRekursionen == 10) { + print("KEINE ANTWORT, CLIENT WIRD BEENDET"); + Thread.sleep(10000); + System.exit(0); + } + start(); + System.exit(0); + + } + + Object erhalten = null; + Message message = new Message("leer", "leer"); + + /** + * Die While Schleife ist der Listener, dieser wartet auf Nachrichten + * aus dem Server und gibt diese dann aus. + * + * Im Falle eines Verindungsabbruches versucht er es 5 mal im Abstand + * von 2 Sekunden nochmal eine Nachricht zu senden und ruft dann wieder + * die start() Methode auf. wodurch die Verbindung nochmal neu + * hergestellt wird. + * + * Die While-Schleife wird abgebrochen, sobald die Nachricht, welche der + * Benutzer über das GUI sendet "exit" lautet. + * + */ + while (!temp.getMessage().equals("exit")) { + //System.out.println("WHILE"); + try { + //System.out.println("hile4"); + System.out.println("Nachricht erhalten"); + erhalten = obinstr.readObject(); //Bleibt hier stehen, bis ein neues Object reinkommt + + message = (Message) erhalten; + System.out.println("[" + message.getUsername() + "] " + message.getMessage()); + String Ausgeben = message.getTime() + " [" + message.getUsername() + "] " + message.getMessage(); + print(Ausgeben); + //System.out.println("[CLIENT] NACHRICHT ERHALTEN"); + + oboust.flush(); + + } catch (SocketException h) { + System.out.println(h); + print("VERBINDUNGSABBRUCH"); + anzahlVersuche++; + + Thread.sleep(2000); + + if (anzahlVersuche == 5) { + anzahlVersuche = 0; + anzahlRekursionen++; + + if (anzahlRekursionen == 10) { + print("KEINE ANTWORT, CLIENT WIRD BEENDET"); + Thread.sleep(10000); + System.exit(0); + + } + + start(); + System.exit(0); + } + + } catch (Exception f) { + Thread.sleep(1000); + } + + } + + /** + * Nach dem Abbruch der While Schleife, was nur bei der Nachricht exit + * passiert, schließt der Client den ObjectOutputstream, + * Objectinputstream und den Socket und beendet dann das Programm + */ + oboust.close(); + obinstr.close(); + socket.close(); + + System.exit(0); + + } } diff --git a/src/client/Client1.java b/src/client/Client1.java index a1e495a..bfce9ee 100644 --- a/src/client/Client1.java +++ b/src/client/Client1.java @@ -20,324 +20,293 @@ import java.awt.event.ActionEvent; /** * Hauptklasse des Clients + * * @version 0.1.3 * @author berdan */ - - public class Client1 extends JFrame { - - /* + /* Hier werden Objekte und Variablen deklariert, damit diese in allen Methoden genutzt werden können. - */ - private static JPanel contentPane; - JTextField txtMessage; - private static JTextField txtUsername; - public static String currentText = " "; - public static int i = 0; - public static Object tosend = new Message("Leer", "Leer"); - public static Client1 t1; - public static Socket socket; - public static ObjectInputStream obinstr; - public static ObjectOutputStream oboust; - public static boolean verbunden = false; - public static JTextArea textArea = new JTextArea(); - public static int anzahlVersuche = 0; //Ist gleich die AN - public static int anzahlRekursionen = 0; - public static Message temp = new Message("leer", "leer"); - - /* + */ + private static JPanel contentPane; + JTextField txtMessage; + private static JTextField txtUsername; + public static String currentText = " "; + public static int i = 0; + public static Object tosend = new Message("Leer", "Leer"); + public static Client1 t1; + public static Socket socket; + public static ObjectInputStream obinstr; + public static ObjectOutputStream oboust; + public static boolean verbunden = false; + public static JTextArea textArea = new JTextArea(); + public static int anzahlVersuche = 0; //Ist gleich die AN + public static int anzahlRekursionen = 0; + public static Message temp = new Message("leer", "leer"); + + /* In der main Methode wird das GUI erstellt und die start() Methode aufgerufen. - */ - - public static void main(String[] args) throws InterruptedException { - t1 = new Client1(); - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - Client1 frame = new Client1(); - frame.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - - - try { - start(); - } catch (ClassNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - - /* + */ + public static void main(String[] args) throws InterruptedException { + t1 = new Client1(); + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + Client1 frame = new Client1(); + frame.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + try { + start(); + } catch (ClassNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /* In der Methode Client1() wird das GUI und die Befehle die durch einen Click des Button's ausgelöst werden festgelegt - */ + */ + public Client1() { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 450, 300); + contentPane = new JPanel(); + contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); + setContentPane(contentPane); + contentPane.setLayout(null); - public Client1() { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(100, 100, 450, 300); - contentPane = new JPanel(); - contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); - setContentPane(contentPane); - contentPane.setLayout(null); - - txtMessage = new JTextField(); - txtMessage.setText("Message"); - txtMessage.setBounds(20, 230, 218, 20); - contentPane.add(txtMessage); - txtMessage.setColumns(10); - - txtUsername = new JTextField(); - txtUsername.setText("Username"); - txtUsername.setBounds(20, 11, 86, 20); - contentPane.add(txtUsername); - txtUsername.setColumns(10); - - - /* - Der Button "Send" nimmt die aktuelle Nachricht, - welche im Textfeld "message" geschrieben wurde und - schreibt diese als ein Message-Objekt in den Output-Stream - an den Server, falls die Socket bereits verbunden ist. - - Falls die Nachricht "exit" sein sollte, wird - die GUI beendet. - */ - - JButton btnSend = new JButton("Send"); - btnSend.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - - if(verbunden){ - - String themessage = txtMessage.getText(); - String theusername = txtUsername.getText(); - - tosend = new Message(theusername, themessage); - i = 1; - - temp = new Message(theusername, themessage); - System.out.println("Button pressed"); + txtMessage = new JTextField(); + txtMessage.setText("Message"); + txtMessage.setBounds(20, 230, 218, 20); + contentPane.add(txtMessage); + txtMessage.setColumns(10); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - try{ - try { - oboust.writeObject(tosend); - oboust.flush(); - } catch (IOException e) { - e.printStackTrace(); - } - } catch( Exception k){ - print("KEINE VERBINDUNG"); - } - - if(temp.getMessage().equals("exit")){ - System.exit(0); - } - - txtMessage.setText(""); + txtUsername = new JTextField(); + txtUsername.setText("Username"); + txtUsername.setBounds(20, 11, 86, 20); + contentPane.add(txtUsername); + txtUsername.setColumns(10); - } + /** + * Der Button "Send" nimmt die aktuelle Nachricht, welche im Textfeld + * "message" geschrieben wurde und schreibt diese als ein Message-Objekt + * in den Output-Stream an den Server, falls die Socket bereits + * verbunden ist. + * + * Falls die Nachricht "exit" sein sollte, wird die GUI beendet. + */ + JButton btnSend = new JButton("Send"); + btnSend.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { - } - }); - - btnSend.setBounds(264, 229, 79, 23); - contentPane.add(btnSend); - - /* - Hier wird die textArea, auf welcher der Text ausgegeben wird - initialisiert - - */ - textArea = new JTextArea(currentText); - textArea.setLineWrap(true); - textArea.setForeground(Color.BLACK); - textArea.setBackground(Color.LIGHT_GRAY); - textArea.setBounds(20, 42, 323, 176); - contentPane.add(textArea); - - /* - Der Start Button sorgt sorgt dafür, dass der Username - festgesetzt wird, wodurch er nicht veränderlich ist. - Außerdem wird die globale Variabel j von 0 auf 1 gestzt, - wodurch die start-Methode weiß, dass sie eine Verbindung - aufbauen soll. - - */ - - JButton btnStart = new JButton("Start"); - btnStart.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent arg0) { - - txtUsername.setEditable(false); - txtUsername.setEnabled(false); - verbunden = true; + if (verbunden) { - } - }); - btnStart.setBounds(116, 10, 89, 23); - contentPane.add(btnStart); - + String themessage = txtMessage.getText(); + String theusername = txtUsername.getText(); - - } - - /* - In der Print-Methode wird der neue Text (also eine neue Nachricht) - auf die textArea abgebildet. - */ - - public static void print(String neuerText){ - currentText = neuerText + "\n" + currentText; + tosend = new Message(theusername, themessage); + i = 1; - textArea.setText(currentText); - } - - /* - Die start-Methode wartet, bis die Variable verbunden durch Klicken - des Start Buttons auf true gesetzt wird, erst dann beginnt die - eigentliche Methode. - - Es wird dann eine Verbindung zum Socket über den Port - 1236 aufgebaut. Sollte dies nicht Möglich sein, wird die - Fehlermeldung in der GUI ausgegeben, sodass der Nutzer weiß, - dass keine Vebrindung möglich ist. - - Es wird im Sekundentakt nach einer neuen Verbindung gesucht. - - */ - - - public static void start() throws IOException, ClassNotFoundException, InterruptedException{ - - while(!verbunden){ - Thread.sleep(100); - } - - txtUsername.setEnabled(false); - Scanner scan = new Scanner(System.in); - - try{ - socket = new Socket( "localhost", 1236 ); - oboust = new ObjectOutputStream(socket.getOutputStream()); - obinstr = new ObjectInputStream(socket.getInputStream()); - print("VERBINDUNG HERGESTELLT"); - }catch(Exception KeineSocket){ - print("SERVER ANTWORTET NICHT"); - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - anzahlRekursionen++; - if(anzahlRekursionen == 10){ - print("KEINE ANTWORT, CLIENT WIRD BEENDET"); - Thread.sleep(10000); - System.exit(0); + temp = new Message(theusername, themessage); + System.out.println("Button pressed"); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + try { + try { + oboust.writeObject(tosend); + oboust.flush(); + } catch (IOException e) { + e.printStackTrace(); } - start(); - System.exit(0); - - } - + } catch (Exception k) { + print("KEINE VERBINDUNG"); + } - Object erhalten = null; - Message message = new Message("leer", "leer"); + if (temp.getMessage().equals("exit")) { + System.exit(0); + } - /* - Die While Schleife ist der Listener, - dieser wartet auf Nachrichten aus dem Server und - gibt diese dann aus. - - Im Falle eines Verindungsabbruches versucht er - es 5 mal im Abstand von 2 Sekunden nochmal eine Nachricht - zu senden und ruft dann wieder die start() Methode auf. - wodurch die Verbindung nochmal neu hergestellt wird. - - Die While-Schleife wird abgebrochen, sobald die Nachricht, - welche der Benutzer über das GUI sendet "exit" lautet. - - */ - + txtMessage.setText(""); - - while(!temp.getMessage().equals("exit")){ - //System.out.println("WHILE"); - try{ - //System.out.println("hile4"); - System.out.println("Nachricht erhalten"); - erhalten = obinstr.readObject(); //Bleibt hier stehen, bis ein neues Object reinkommt + } - message = (Message)erhalten; - System.out.println("[" + message.getUsername() + "] " + message.getMessage()); - String Ausgeben = message.getTime() + " [" + message.getUsername() + "] " + message.getMessage(); - print(Ausgeben); - //System.out.println("[CLIENT] NACHRICHT ERHALTEN"); - - oboust.flush(); + } + }); - } + btnSend.setBounds(264, 229, 79, 23); + contentPane.add(btnSend); - catch(SocketException h){ - System.out.println(h); - print("VERBINDUNGSABBRUCH"); - anzahlVersuche++; - - Thread.sleep(2000); + /** + * Hier wird die textArea, auf welcher der Text ausgegeben wird + * initialisiert + * + */ + textArea = new JTextArea(currentText); + textArea.setLineWrap(true); + textArea.setForeground(Color.BLACK); + textArea.setBackground(Color.LIGHT_GRAY); + textArea.setBounds(20, 42, 323, 176); + contentPane.add(textArea); - - if(anzahlVersuche==5){ - anzahlVersuche = 0; - anzahlRekursionen++; - - if(anzahlRekursionen == 10){ - print("KEINE ANTWORT, CLIENT WIRD BEENDET"); - Thread.sleep(10000); - System.exit(0); - - } - - - start(); - System.exit(0); - } - - } - catch(Exception f){ - Thread.sleep(1000); - } - - } - - /* - Nach dem Abbruch der While Schleife, was nur bei der - Nachricht exit passiert, schließt der Client - den ObjectOutputstream, Objectinputstream und den Socket - und beendet dann das Programm - */ + /** + * Der Start Button sorgt sorgt dafür, dass der Username festgesetzt + * wird, wodurch er nicht veränderlich ist. Außerdem wird die globale + * Variabel j von 0 auf 1 gestzt, wodurch die start-Methode weiß, dass + * sie eine Verbindung aufbauen soll. + * + */ + JButton btnStart = new JButton("Start"); + btnStart.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent arg0) { - oboust.close(); - obinstr.close(); - socket.close(); - - System.exit(0); - - - - } + txtUsername.setEditable(false); + txtUsername.setEnabled(false); + verbunden = true; + + } + }); + btnStart.setBounds(116, 10, 89, 23); + contentPane.add(btnStart); + + } + + /** + * In der Print-Methode wird der neue Text (also eine neue Nachricht) auf + * die textArea abgebildet. + */ + public static void print(String neuerText) { + currentText = neuerText + "\n" + currentText; + + textArea.setText(currentText); + } + + /** + * Die start-Methode wartet, bis die Variable verbunden durch Klicken des + * Start Buttons auf true gesetzt wird, erst dann beginnt die eigentliche + * Methode. + * + * Es wird dann eine Verbindung zum Socket über den Port 1236 aufgebaut. + * Sollte dies nicht Möglich sein, wird die Fehlermeldung in der GUI + * ausgegeben, sodass der Nutzer weiß, dass keine Vebrindung möglich ist. + * + * Es wird im Sekundentakt nach einer neuen Verbindung gesucht. + * + */ + public static void start() throws IOException, ClassNotFoundException, InterruptedException { + + while (!verbunden) { + Thread.sleep(100); + } + + txtUsername.setEnabled(false); + Scanner scan = new Scanner(System.in); + + try { + socket = new Socket("localhost", 1236); + oboust = new ObjectOutputStream(socket.getOutputStream()); + obinstr = new ObjectInputStream(socket.getInputStream()); + print("VERBINDUNG HERGESTELLT"); + } catch (Exception KeineSocket) { + print("SERVER ANTWORTET NICHT"); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + anzahlRekursionen++; + if (anzahlRekursionen == 10) { + print("KEINE ANTWORT, CLIENT WIRD BEENDET"); + Thread.sleep(10000); + System.exit(0); + } + start(); + System.exit(0); + + } + + Object erhalten = null; + Message message = new Message("leer", "leer"); + + /** + * Die While Schleife ist der Listener, dieser wartet auf Nachrichten + * aus dem Server und gibt diese dann aus. + * + * Im Falle eines Verindungsabbruches versucht er es 5 mal im Abstand + * von 2 Sekunden nochmal eine Nachricht zu senden und ruft dann wieder + * die start() Methode auf. wodurch die Verbindung nochmal neu + * hergestellt wird. + * + * Die While-Schleife wird abgebrochen, sobald die Nachricht, welche der + * Benutzer über das GUI sendet "exit" lautet. + * + */ + while (!temp.getMessage().equals("exit")) { + //System.out.println("WHILE"); + try { + //System.out.println("hile4"); + System.out.println("Nachricht erhalten"); + erhalten = obinstr.readObject(); //Bleibt hier stehen, bis ein neues Object reinkommt + + message = (Message) erhalten; + System.out.println("[" + message.getUsername() + "] " + message.getMessage()); + String Ausgeben = message.getTime() + " [" + message.getUsername() + "] " + message.getMessage(); + print(Ausgeben); + //System.out.println("[CLIENT] NACHRICHT ERHALTEN"); + + oboust.flush(); + + } catch (SocketException h) { + System.out.println(h); + print("VERBINDUNGSABBRUCH"); + anzahlVersuche++; + + Thread.sleep(2000); + + if (anzahlVersuche == 5) { + anzahlVersuche = 0; + anzahlRekursionen++; + + if (anzahlRekursionen == 10) { + print("KEINE ANTWORT, CLIENT WIRD BEENDET"); + Thread.sleep(10000); + System.exit(0); + + } + + start(); + System.exit(0); + } + + } catch (Exception f) { + Thread.sleep(1000); + } + + } + + /** + * Nach dem Abbruch der While Schleife, was nur bei der Nachricht exit + * passiert, schließt der Client den ObjectOutputstream, + * Objectinputstream und den Socket und beendet dann das Programm + */ + oboust.close(); + obinstr.close(); + socket.close(); + + System.exit(0); + + } } diff --git a/src/server/ClientReciveMessageThread.java b/src/server/ClientReciveMessageThread.java index bf54822..9c7f191 100644 --- a/src/server/ClientReciveMessageThread.java +++ b/src/server/ClientReciveMessageThread.java @@ -25,15 +25,36 @@ import java.util.logging.Logger; import utils.Message; /** - * Diese Klasse stellt einen Thread dar, der auf Nachrichten eines Clients lauscht und diese dann weiter gibt. - * + * Diese Klasse stellt einen Thread dar, der auf Nachrichten eines Clients + * lauscht und diese dann weiter gibt. + * + * @version 1.0.0 * @author eichehome */ public class ClientReciveMessageThread extends Thread { + /** + * Attribut, welches einen Zeiger auf das zentrale Verzeichnis aller + * verbundenen Clients enthält. + */ private ClientStore clientStore; + /** + * Attribut, welches den von Client kommenden Stream repräsentiert. + */ private final ObjectInputStream in; + /** + * Konstruktor + * + * @param in Stream, in dem die Nachrichten eines Clients ankommen. + * @param clientStore Zeiger auf das zentrale Verzeichnis der Clients, um + * alle benachrichtigen zu können. + */ + public ClientReciveMessageThread(ObjectInputStream in, ClientStore clientStore) { + this.in = in; + this.clientStore = clientStore; + } + /** * Hauptmethode des Threads, in der alles abläuft. */ @@ -42,18 +63,18 @@ public class ClientReciveMessageThread extends Thread { boolean continueLoop = true; while (continueLoop) { try { - Message empfangen = null; - while ((empfangen = (Message) this.in.readObject()) != null) { - Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.INFO, String.format("Reciveing Thread %d: Time: %s Client: %s Message: %s", this.getId(), empfangen.getTime(), empfangen.getUsername(), empfangen.getMessage())); - for (ObjectOutputStream stream : clientStore.getAllOutputStreams()) { - stream.writeObject(empfangen); - stream.flush(); - Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.INFO, String.format("Reciveing Thread %d: Weitergeleitet", this.getId())); + Message empfangen = null; + while ((empfangen = (Message) this.in.readObject()) != null) {//Der Thread pleibt hier stehen bis er eine Nachricht vom Client erhält. + Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.INFO, String.format("Reciveing Thread %d: Time: %s Client: %s Message: %s", this.getId(), empfangen.getTime(), empfangen.getUsername(), empfangen.getMessage())); + for (ObjectOutputStream stream : clientStore.getAllOutputStreams()) { + stream.writeObject(empfangen); + stream.flush(); + Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.INFO, String.format("Reciveing Thread %d: Weitergeleitet", this.getId())); + } } - } } catch (ClassNotFoundException ex) { Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.SEVERE, String.format("Reciveing Thread %d: Fehler: %s", this.getId(), ex)); - } catch (EOFException ex) { + } catch (EOFException ex) {//Diese Exception zeigt, dass sich die Verbundung zum Client geschlossen hat. Die Aufräumarbeiten übernimmt der Sending Thread diese Clients. Logger.getLogger(ClientReciveMessageThread.class.getName()).log(Level.INFO, String.format("Reciveing Thread %d: Socket wurde beendet", this.getId())); continueLoop = false; } catch (IOException ex) { @@ -63,13 +84,4 @@ public class ClientReciveMessageThread extends Thread { } } - /** - * Konstruktor - * @param in Stream, in dem die Nachrichten eines Clients ankommen. - * @param clientStore Zeiger auf das zentrale Verzeichnis der Clients, um alle benachrichtigen zu können. - */ - public ClientReciveMessageThread(ObjectInputStream in, ClientStore clientStore) { - this.in = in; - this.clientStore = clientStore; - } } diff --git a/src/server/ClientPushMessageThread.java b/src/server/ClientSendMessageThread.java similarity index 55% rename from src/server/ClientPushMessageThread.java rename to src/server/ClientSendMessageThread.java index 2058154..3078aea 100644 --- a/src/server/ClientPushMessageThread.java +++ b/src/server/ClientSendMessageThread.java @@ -25,54 +25,73 @@ import java.util.logging.Logger; import utils.Message; /** - * Diese Klasse stellt einen Thread dar, die Nachrichten, die er in einem Stream erhällt an einen Client weiterleitet. - * + * Diese Klasse stellt einen Thread dar, die Nachrichten, die er in einem Stream + * erhällt an einen Client weiterleitet. + * + * @version 1.0.0 * @author eichehome */ -public class ClientPushMessageThread extends Thread { +public class ClientSendMessageThread extends Thread { + /** + * Attribut, welches den Stream enthält, in dem die Nachrichten an den + * Client geschickt werden. + */ private final ObjectOutputStream out; + /** + * Attribut, welches den Stream enthält, in dem die Nachrichten ankommen, + * die an den Client geschickt werden sollen. + */ private final ObjectInputStream pipedObjectInputStream; + /** + * Attribut, welches einen Zeiger auf das zentrale Verzeichnis aller + * verbundenen Clients enthält. + */ private ClientStore clientStore; /** - * Haupt methode der Threads, in der alles abläuft. + * Konstruktor + * + * @param out Stream, in dem der Thread die Nachrichten an den Client + * schickt. + * @param pipedObjectInputStream Stream, in dem der Thread die Nachrichten + * von anderen Threads erhält. + * @param clientStore Zeiger auf das zentrale Verzeichnis der Clients, um + * sich dort austragen zu können. + */ + public ClientSendMessageThread(ObjectOutputStream out, ObjectInputStream pipedObjectInputStream, ClientStore clientStore) { + this.out = out; + this.pipedObjectInputStream = pipedObjectInputStream; + this.clientStore = clientStore; + } + + /** + * Hauptmethode der Threads, in der alles abläuft. */ public void run() { boolean continueLoop = true; while (continueLoop) { try { Message empfangen = null; - while ((empfangen = (Message) this.pipedObjectInputStream.readObject()) != null) { + while ((empfangen = (Message) this.pipedObjectInputStream.readObject()) != null) {//Hier bleibt dieser Thread stehen bis er eine Nchricht erhält, die er an den Client weiterleiten soll. this.out.writeObject(empfangen); this.out.flush(); - Logger.getLogger(ClientPushMessageThread.class.getName()).log(Level.INFO, String.format("Pushing Thread %d: Nachricht weitergegeben", this.getId())); + Logger.getLogger(ClientSendMessageThread.class.getName()).log(Level.INFO, String.format("Sending Thread %d: Nachricht weitergegeben", this.getId())); } } catch (ClassNotFoundException ex) { - Logger.getLogger(ClientPushMessageThread.class.getName()).log(Level.SEVERE, String.format("Pushing Thread %d: Fehler: %s", this.getId(), ex)); + Logger.getLogger(ClientSendMessageThread.class.getName()).log(Level.SEVERE, String.format("Sending Thread %d: Fehler: %s", this.getId(), ex)); } catch (EOFException ex) { - Logger.getLogger(ClientPushMessageThread.class.getName()).log(Level.SEVERE, String.format("Pushing Thread %d: Fehler: %s", this.getId(), ex)); + Logger.getLogger(ClientSendMessageThread.class.getName()).log(Level.SEVERE, String.format("Sending Thread %d: Fehler: %s", this.getId(), ex)); continueLoop = false; - clientStore.close(this); - clientStore.removeClient(this); - } catch (IOException ex) { - Logger.getLogger(ClientPushMessageThread.class.getName()).log(Level.INFO, String.format("Pushing Thread %d: Pipe wurde beendet", this.getId())); - clientStore.removeClient(this); + this.clientStore.close(this); + this.clientStore.removeClient(this); + } catch (IOException ex) {//Diese Exeption zeigt, dass sich der Stream zum Client geschlossen hat und deshalb Aufräumarbeiten angebracht sind. + Logger.getLogger(ClientSendMessageThread.class.getName()).log(Level.INFO, String.format("Sending Thread %d: Pipe wurde beendet", this.getId())); + this.clientStore.close(this); + this.clientStore.removeClient(this); continueLoop = false; } } } - /** - * Konstruktor - * @param out Stream, in dem der Thread die Nachrichten an den Client schickt. - * @param pipedObjectInputStream Stream, in dem der Thread die Nachrichten von anderen Threads erhält. - * @param clientStore Zeiger auf das zentrale Verzeichnis der Clients, um sich dort austragen zu können. - */ - public ClientPushMessageThread(ObjectOutputStream out, ObjectInputStream pipedObjectInputStream, ClientStore clientStore) { - this.out = out; - this.pipedObjectInputStream = pipedObjectInputStream; - this.clientStore = clientStore; - } - } diff --git a/src/server/ClientStore.java b/src/server/ClientStore.java index c971a75..2f8821c 100644 --- a/src/server/ClientStore.java +++ b/src/server/ClientStore.java @@ -23,23 +23,29 @@ import java.util.logging.Level; import utils.Client; /** - * Diese Klasse Stellt das zentrale Verzeichniss aller Clients dar. - * + * Diese Klasse stellt das zentrale Verzeichniss aller Clients dar. + * + * @version 1.0.0 * @author eichehome */ public class ClientStore { - - private Client[] clients = null; - + /** - * Diese Funktion fügt einen Client dem Verzeichniss aller Clients hinzu, die Verbunden sind. + * Attribut, welches ein Array aller verbundenen Clients enthält. + */ + private Client[] clients = null; + + /** + * Funktion, welche einen Client dem Verzeichniss aller verbundenen Clients + * hinzufügt. + * * @param newClient Der neue Client, der hinzugefügt werden soll. */ public void addClient(Client newClient) { if (this.clients != null) { Client[] temp = new Client[this.clients.length + 1]; System.arraycopy(clients, 0, temp, 0, clients.length); - temp[temp.length - 1] = newClient; + temp[temp.length - 1] = newClient;//Letzter Eintrag ist der neue Client. this.clients = temp; } else { Client[] temp = new Client[1]; @@ -48,30 +54,34 @@ public class ClientStore { } Logger.getLogger(ClientStore.class.getName()).log(Level.INFO, "ClientStore: Client hinzugefügt"); } - + /** - * Dies Funktion entfernt einen Client aus dem Verzeichnis aller verbundenen Clients. - * @param pusher Der Pusher-Thread des Clients, welcher aus dem Verzeichnis entfernt werden soll. + * Funktion, welche einen Client aus dem Verzeichnis aller verbundenen + * Clients entfernt. + * + * @param sender Der Pusher-Thread des Clients, welcher aus dem Verzeichnis + * entfernt werden soll. * @return Gibt die zu dem Client gehörenden Streams und Threads zurück. - * @throws IllegalArgumentException Falls der Thread nicht existiert oder keine Clients vorhanden sind, wird eine Exeption mit der passenden Fehlermeldung geworfen. + * @throws IllegalArgumentException Falls der Thread nicht existiert oder + * keine Clients vorhanden sind, wird eine Exeption mit der passenden + * Fehlermeldung geworfen. */ - public Client removeClient(Thread pusher) throws IllegalArgumentException { + public Client removeClient(Thread sender) { if (this.clients != null) { int index = -1; + //Suche nach dem Element in dem Array for (int i = 0; i < this.clients.length; i++) { - if (this.clients[i].getPusher().equals(pusher)) { + if (this.clients[i].getSender().equals(sender)) { index = i; break; } } if (index != -1) { Client[] temp = new Client[this.clients.length - 1]; - for (int i = 0; i < index; i++) { - temp[i] = this.clients[i]; - } - for (int i = (index + 1); i < this.clients.length; i++) { - temp[i - 1] = this.clients[i]; - } + //Teil des Arrays vor dem Index des zu entfernenden Elements kopieren. + System.arraycopy(this.clients, 0, temp, 0, index); + //Teil des Arrays nach dem Index des zu entfernenden Elements 1 Index nach vorne kopieren. + System.arraycopy(this.clients, (index + 1), temp, index, (this.clients.length - (index + 1))); Client result = this.clients[index]; this.clients = temp; Logger.getLogger(ClientStore.class.getName()).log(Level.INFO, "ClientStore: Client gelöscht"); @@ -83,9 +93,11 @@ public class ClientStore { throw new IllegalArgumentException("No clients present"); } } - + /** - * Diese Funktion gibt alle Streams zu den Clients zurück, die derzeit Verbunden sind. + * Funktion, welche alle Streams zu den Clients, die derzeit Verbunden sind, + * zurückgibt. + * * @return Ein Array aus allen Streams */ public ObjectOutputStream[] getAllOutputStreams() { @@ -96,17 +108,20 @@ public class ClientStore { Logger.getLogger(ClientStore.class.getName()).log(Level.INFO, "ClientStore: Alle Streams zusammengesucht"); return streams; } - + /** - * Schließt den zu einem Thread gehörenden OutputStream - * @param thread Der Thread, dessen OutputStream geschlossen werden soll - * @throws IllegalArgumentException Falls der Thread nicht existiert oder keine Clients vorhanden sind, wird eine Exeption mit der passenden Fehlermeldung geworfen. + * Funktion, die den zu einem Thread gehörenden OutputStream schließt. + * + * @param sender Der Thread, dessen OutputStream geschlossen werden soll + * @throws IllegalArgumentException Falls der Thread nicht existiert oder + * keine Clients vorhanden sind, wird eine Exeption mit der passenden + * Fehlermeldung geworfen. */ - public void close(Thread thread) throws IllegalArgumentException{ + public void close(Thread sender) { if (this.clients != null) { int index = -1; for (int i = 0; i < this.clients.length; i++) { - if (clients[i].getPusher().equals(thread)) { + if (this.clients[i].getSender().equals(sender)) { index = i; } } @@ -123,5 +138,5 @@ public class ClientStore { throw new IllegalArgumentException("No Clients Present"); } } - + } diff --git a/src/server/MainServer.java b/src/server/MainServer.java index 1890070..87fb9e3 100644 --- a/src/server/MainServer.java +++ b/src/server/MainServer.java @@ -20,7 +20,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; -import java.net.*; +import java.net.ServerSocket; +import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; import utils.Client; @@ -28,13 +29,13 @@ import utils.Client; /** * Hauptklasse des Servers * - * @version 0.0.1 + * @version 1.0.0 * @author eichehome */ public class MainServer { /** - * Einstiegsklasse des Servers. Diese wartet auf Anfragen der Clients und erstellt dann die nötigen Resourcen (Streams und Threads). + * Einstiegsfunktion des Servers, welche auf Anfragen der Clients wartet und dann die nötigen Resourcen (Streams und Threads) erstellt. * @param args the command line arguments */ public static void main(String[] args) { @@ -42,7 +43,7 @@ public class MainServer { ClientStore clientStore = new ClientStore(); while (true) { Logger.getLogger(MainServer.class.getName()).log(Level.INFO, String.format("Main: Warte auf Clients")); - Socket client = serverSocket.accept(); + Socket client = serverSocket.accept();//Hier bleibt der server stehen und geht erst weiter wenn ein Client sich verbinden will. Logger.getLogger(MainServer.class.getName()).log(Level.INFO, String.format("Main: Client verbunden")); PipedOutputStream pipedOutputStream = new PipedOutputStream(); @@ -57,16 +58,16 @@ public class MainServer { Logger.getLogger(MainServer.class.getName()).log(Level.INFO, String.format("Main: Streams erstellt")); Thread threadRecive = new ClientReciveMessageThread(in, clientStore); - Thread threadPush = new ClientPushMessageThread(out, pipedObjectInputStream, clientStore); + Thread threadSend = new ClientSendMessageThread(out, pipedObjectInputStream, clientStore); Logger.getLogger(MainServer.class.getName()).log(Level.INFO, String.format("Main: Threads erstellt")); - threadPush.start(); + threadSend.start(); threadRecive.start(); Logger.getLogger(MainServer.class.getName()).log(Level.INFO, String.format("Main: Threads gestartet")); - clientStore.addClient(new Client(pipedObjectOutputStream, threadPush, threadRecive)); + clientStore.addClient(new Client(pipedObjectOutputStream, threadSend, threadRecive)); } } catch (Exception ex) { diff --git a/src/utils/Client.java b/src/utils/Client.java index 3b18770..2810ab3 100644 --- a/src/utils/Client.java +++ b/src/utils/Client.java @@ -18,44 +18,64 @@ package utils; import java.io.IOException; import java.io.ObjectOutputStream; +import java.util.logging.Logger; +import java.util.logging.Level; /** * Dies Klasse stellt einen Client mit seinen Streams dar. - * + * + * @version 1.0.0 * @author eichehome */ public class Client { + /** + * Attribut, welches den Stream enthält, in dem Nachrichten an den Thread + * geschickt werden können, der diese an den Client weiterleitet. + */ private final ObjectOutputStream out; - private final Thread pusher; + /** + * Attribut, welches einen Zeiger auf den Thread enthält, welcher + * Nachrichten an den Client schickt. + */ + private final Thread sender; + /** + * Attribut, welches einen Zeiger auf den Thread enthält, welcher + * Nachrichten von dem Client empfängt. + */ private final Thread reciver; /** * Konstruktor + * * @param out Stream, um diesem Client Nachrichten schicken zu können. - * @param pusher Zeiger auf den Thread, der die Nachrichten an den Client sendet. - * @param reciver Zeiger auf den Thread, der die Nachrichten eines Clients empfängt. + * @param sender Zeiger auf den Thread, der die Nachrichten an den Client + * sendet. + * @param reciver Zeiger auf den Thread, der die Nachrichten eines Clients + * empfängt. */ - public Client(ObjectOutputStream out, Thread pusher, Thread reciver) { + public Client(ObjectOutputStream out, Thread sender, Thread reciver) { this.out = out; - this.pusher = pusher; + this.sender = sender; this.reciver = reciver; } /** * Schreibe eine Nachricht in den OutputStream dieses Clients. + * * @param message Die zu verschickende Nachricht. */ public void writeMessage(Message message) { try { - this.out.writeObject(message); + this.out.writeObject(message); } catch (IOException ex) { - System.err.println("Cliet: Fehler: " + ex); + Logger.getLogger(Client.class.getName()).log(Level.SEVERE, String.format("Client: Fehler: %s", ex)); } } /** * Getter für den OutputStream diese Clients + * * @return Zeiger auf den Stream. */ public ObjectOutputStream getOutputStream() { @@ -64,14 +84,16 @@ public class Client { /** * Getter für den Thread, der Nachrichten an diesen Client sendet. + * * @return Zeiger auf den Thread. */ - public Thread getPusher() { - return this.pusher; + public Thread getSender() { + return this.sender; } - + /** * Getter für den Thread, der Nchrichten an diesen Client sendet. + * * @return Zeiger auf den Thread. */ public Thread getReciver() {