Sockets und Events



  • Hi JavaGöTTeR 🙂

    ich habe mal eine Frage, ich möchte auf einem "Server" ein Fenster haben auf dem ich malen kann (habe ich schon) und auf dem Client soll dann über dem Socket die Änderung übernommen werden ( dort gibt es auch so ein Fenster )

    Also man malt auf dem Server und der/alle Clients sehen es dann so schnell es die Verbindung zulässt.

    Es soll ein Objekt gesendet werden also wie wärs mit dem mouseEvent ? Denn dann einfach an den Client senden? Ich weiß nicht genau wie ich da vorgehen soll...also wo ich die Sockets einbauen soll und was genau sie senden sollen...habt ihr eine Idee?

    package ownSocketsT;
    
    	/**
    	  * BlackBoardServer.java	
    	  * @author paff
    	  * @version 1.0
    	  */
    	 import javax.swing.*;
    	 import java.awt.*;
    	 import java.awt.event.*;
    	 import java.io.*;
    import java.net.*;
    import java.util.Date;
    
    	 //Die Klasse BlackBoardClient erweitert die Klasse JFrame.
    	 public class BlackBoardServer extends JFrame
    	 {
    
    	   //Konstruktor der Klasse BlackBoardClient
    	   public BlackBoardServer() {
    
    	     //Konstruktor der Superklasse wird aufgerufen.
    	     super("Server...");
    
    	     //Objekt der Klasse Zeichenflaeche wird erzeugt.
    	     Zeichenflaeche label = new Zeichenflaeche();
    
    	     //Inhaltsbereich wird abgefragt und Zeichenfläche eingefügt.
    	     Container contentPane = getContentPane();
    	     contentPane.add(label);
    
    	     WindowListener listener = new WindowAdapter()
    	     {
    	 	      public void windowClosing(WindowEvent e)
    	 	      {
    	 	        System.exit(0);
    	 	      }
    	     };
    
    	    this.addWindowListener(listener);
    	 	this.setSize(300, 200);
    	    this.setVisible(true);
    	   }
    
    	   public static void main(String[] args) 
    	   {
    		   BlackBoardServer jframe = new BlackBoardServer()
    	   }
    	 }
    	 class Zeichenflaeche extends JLabel 
    	 {
    	   int xa = 0;
    	   int ya = 0;
    	   public Zeichenflaeche()
    	   {
    	     this.addMouseMotionListener (new MouseMotionListener()
    	     {
    	       public void mouseDragged( MouseEvent me ) 
    	       {
    	         int x = me.getX();
    	         int y = me.getY();
    	         xa = x;
    	         ya = y;
    	         repaint( xa, ya, 5, 5);
    	         // Hier auch senden???
    	       }
    	       public void mouseMoved( MouseEvent me ) {}
    	      });
    	    }
    	   public void paintComponent(Graphics g)
    	   {
    	     super.paintComponent(g);
    	     g.fillOval( xa, ya, 5, 5);
    	   }
    	 }
    


  • MouseEvent implementiert Serializable:

    public class Blubba extends JFrame implements MouseListener
    {
        public Blubba ()
        {
            this.addMouseListener(this);
        }
    
        // Nachricht die den anderen interessiert behandeln:
        void mouseClicked (MouseEvent ev) { sockOutStream.send(ev); }
    
        // Nachricht die den anderen nicht interessiert ignorieren:
        void mouseExited (MouseEvent ev) { /* do nothing */ }
    }
    

    Wenn MouseEvent allerdings viel zu viel Information für dich bietet dann versendest du viel zu viele Daten über das Netzwerk und deine Applikation wird langsam. In dem Fall sende nur Daten die dich wirklich interessieren, something like that:

    void mouseReleased (MouseEvent ev) { sockOutStream.send("MSREL " + ev.getX() + "/" + ev.getY() + "|"); }
    

    Dabei dient | als Trennzeichen zwischen Nachrichten. Der Client parst dann diese Daten und führt die Aktion ebenfalls durch. Das wär dann ein kleines Protokoll.

    MfG SideWinder



  • Danke das hilft mir schonmal weiter 🙂

    ok ich sende dann den MouseEvent aber wo soll ich den lesen? Eigentlich dessen main-methode und dort würde ich dann bei jedem erfolgreichem readObj selbst einen mouseEvent auf dem Client auslösen? Wenn ja wie mache ich das denn eigentlich selbst?



  • PaFF schrieb:

    Danke das hilft mir schonmal weiter 🙂

    ok ich sende dann den MouseEvent aber wo soll ich den lesen? Eigentlich dessen main-methode und dort würde ich dann bei jedem erfolgreichem readObj selbst einen mouseEvent auf dem Client auslösen? Wenn ja wie mache ich das denn eigentlich selbst?

    Threading ist dir ein Begriff? Wenn nicht wirds Zeit 😉 Der Server hat also folgende Features:

    1. MouseListener fürs Panel
    2. Events die bei den Clients auch ausgeführt werden sollen: In irgendeiner Form versenden (entweder direkt, oder besser wohl über selbstgemachtes Protkoll)

    Clients haben folgende Features:

    1. main-Thread in der der User seinen Aufgaben nachgehen kann
    2. receive-Thread der Nachrcihten vom Server empfängt und sie auswertet (umsetzt)

    Warum selbstgemachtes Protkoll? Naja du wirst in naher Zukunft dann nicht nur von den MouseEvents selbst wissen wollen, sondern zB auch mit welchem Tool dieses MouseEvent gemacht wurde (Stift, Radiergummi, etc.). Das wird dann über das MouseEvent unübersichtlich.

    MfG SideWinder



  • Hmm ok aber der Client soll wirklich eigentlich nur die Objekte die der Server ihm schickt verarbeiten...

    mir stellt sich jetzt die Frage wie ich den mouseEvent aus dem Server zu einem mouseEvent im Client mache, also auf dem Server "abgreifen" an den client schicken, das passiert ja schon, doch wo "lausche" ich jetzt auf diese events und verarbeite sie...wie gesagt ich denke falls ich solche events selber auslösen kann wäre es auch kein problem...



  • So versuche ich es aber es klappt leider nicht....wie bringe ich "ihn" dazu zu "denken" das die maus bei "ihm" geklickt wurde und die mousdragged-routine mit dem mouseEvent den ich gesendet habe aufzurufen?

    package ownSocketsT;
    
    	/**
    	002  * InEinFensterZeichnen.java
    	003  * Erzeugt einfaches Swing-Fenster
    	004  * in das gezeichnet werden kann.
    	005  * @author paff
    	006  * @version 1.0
    	007  */
    	 import javax.swing.*;
    
    	 import java.awt.*;
    import java.awt.event.*;
    import java.io.BufferedInputStream;
    import java.io.ObjectInputStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Date;
    
    	 //Die Klasse BlackBoardClient erweitert die Klasse JFrame.
    	 public class BlackBoardClient extends JFrame
    	 {
    		 static Socket socket;
    		 static ObjectInputStream ois;
    
    	   //Konstruktor der Klasse BlackBoardClient
    	   public BlackBoardClient() {
    
    	     //Konstruktor der Superklasse wird aufgerufen.
    	     super("Malen mit der Maus...");
    
    	     //Objekt der Klasse Zeichenflaeche wird erzeugt.
    	     Zeichenflaeche label = new Zeichenflaeche();
    
    	     //Inhaltsbereich wird abgefragt und Zeichenfläche eingefügt.
    	     Container contentPane = getContentPane();
    	     contentPane.add(label);
    
    	     WindowListener listener = new WindowAdapter()
    	     {
    	 	      public void windowClosing(WindowEvent e)
    	 	      {
    	 	        System.exit(0);
    	 	      }
    	     };
    
    	    this.addWindowListener(listener);
    	 	this.setSize(300, 200);
    	    this.setVisible(true);
    	   }
    
    	   public static void main(String[] args) 
    	   {
    		   BlackBoardClient jframe = new BlackBoardClient();
    			try 
    			{
    				socket = new Socket ("localhost" , 6666 );
    			    new ObjectInputStream (new BufferedInputStream ( socket . getInputStream ()));
    			    while( true)
    			    {
    			    	Object o = ois. readObject ();
    			    	Event me = (Event) o; 
    			    	jframe.mouseDrag(me , 100, 200);			    	
    				//	jframe.mouseDrag(null, i.intValue(), i.intValue());
    			    	System.out.println( me );
    			    }
    
    				//socket.close();
    			} 
    			catch ( UnknownHostException e) 
    			{
    				System . err. println (" Host  nicht gefunden");
    			}
    			catch ( Exception ex)
    			{
    
    			}
    		   //jframe.mouseDrag(null, 1655, 1455);
    	   }
    
    	   class Zeichenflaeche extends JLabel 
    		 {
    		   int xa = 0;
    		   int ya = 0;
    		   public Zeichenflaeche()
    		   {
    		     this.addMouseMotionListener (new MouseMotionListener()
    		     {
    		       public void mouseDragged( MouseEvent me ) 
    		       {
    		         int x = me.getX();
    		         int y = me.getY();
    		         xa = x;
    		         ya = y;
    		         repaint( xa, ya, 5, 5);
    		         // Hier auch senden???
    		       }
    		       public void mouseMoved( MouseEvent me ) {}
    		      });
    		    }
    		   public void paintComponent(Graphics g)
    		   {
    		     super.paintComponent(g);
    		     g.fillOval( xa, ya, 5, 5);
    		   }
    		 }
    	 }
    


  • Dein Lösungsansatz tatsächlich den Mausklick zu simulieren ist nicht das gelbe vom Ei. Du solltest nicht HID-Events verschicken sondern nur Aktionen ala "Kreis mit Koordinaten 3,3 und 6,6 gezeichnet" versenden, die dein Client-Programm dann verarbeiten kann.

    Deswegen habe ich dir ja auch zu einem eigenen kleinen Protokoll geraten anstatt MouseEvents zu versenden!

    MfG SideWinder



  • ja du hast natürlich recht wenn es darum geht eine saubere und effektive Lösung zu entwicklen , ich brauche es aber gerade nur quick und dirty.

    Aber gut sagen wir ich schicke wirklich nur das wesentliche an Daten, so komme ich doch nicht drumherrum irgendwie die PaintComponent-Methode des Labels aufzurufen und da komme ich jetzt in der main-methode irgendwie schlecht dran ?!

    Sorry vielleicht ist es auch ganz leicht...das letzte Mal das ich Oberflächen in Java gemacht habe ist schon zwei Jahre her...



  • An jFrame.repaint() kommst du doch überall?

    MfG SideWinder



  • Das Problem ist einfach das ich ja immer nur einen bestimmten Bereich neu zeichne damit die anderen "Punkte" auch erhalten bleiben...



  • Du könntest auch die Robot-Klasse benutzen; mit der kann man dann die Maus bewegen lassen. Ist halt fraglich ob am Client die Voraussetzungen (Fokus im Fenster etc.) erfüllt sind.



  • Ja es klappt leider nicht , liegt warscheinlich wirklich an der Focus-geschichte...



  • Das Beste ist immer noch das Marshalling also das Schicken von Nachrichten an die Clients, sie mögen doch bitte so nett sein und das und jenes Objekt zeichnen.



  • Ich komme absolut nicht weiter...eigentlich müsste es doch klappen aber irgendwie kommen die Events nicht rüber obwohl die Socketverbindung eigentlich klappen müsste....ich führe zuerst den Server und dann den Client aus, die Klassen sehen so aus( ich bin echt verzweifelt :-() :

    package ownSocketsT;
    
    	/**
    	  * BlackBoardServer.java	
    	  * @author paff
    	  * @version 1.0
    	  */
    	 import javax.swing.*;
    	 import java.awt.*;
    	 import java.awt.event.*;
    	 import java.io.*;
    import java.net.*;
    import java.util.Date;
    
    	 //Die Klasse BlackBoardClient erweitert die Klasse JFrame.
    	 public class BlackBoardServer extends JFrame
    	 {
    
    		 static ServerSocket socket ;
    		 static Socket clientSocket ;
    		 static ObjectOutputStream oos;
    	   //Konstruktor der Klasse BlackBoardClient
    	   public BlackBoardServer() {
    
    	     //Konstruktor der Superklasse wird aufgerufen.
    	     super("Server...");
    
    	     //Objekt der Klasse Zeichenflaeche wird erzeugt.
    	     Zeichenflaeche label = new Zeichenflaeche();
    
    	     //Inhaltsbereich wird abgefragt und Zeichenfläche eingefügt.
    	     Container contentPane = getContentPane();
    	     contentPane.add(label);
    
    	     WindowListener listener = new WindowAdapter()
    	     {
    	 	      public void windowClosing(WindowEvent e)
    	 	      {
    	 	        System.exit(0);
    	 	      }
    	     };
    
    	    this.addWindowListener(listener);
    	 	this.setSize(300, 200);
    	    this.setVisible(true);
    	   }
    
    	   public static void main(String[] args) 
    	   {
    		   BlackBoardServer jframe = new BlackBoardServer();
    
    			try 
    			{
    				socket = new ServerSocket ( 6666 );
    				clientSocket = socket . accept ();
    	     		System . out. println (" Anfrage von "+ clientSocket . getInetAddress ());
    				oos = new ObjectOutputStream ( clientSocket. getOutputStream()); 		
    			} 
    			catch ( IOException e) 
    			{
    				e. printStackTrace ();
    			}
    	   }
    
    	   class Zeichenflaeche extends JLabel 
    		 {
    		   int xa = 0;
    		   int ya = 0;
    		   public Zeichenflaeche()
    		   {
    		     this.addMouseMotionListener (new MouseMotionListener()
    		     {
    		       public void mouseDragged( MouseEvent me ) 
    		       {
    		         int x = me.getX();
    		         int y = me.getY();
    		         xa = x;
    		         ya = y;
    		         repaint( xa, ya, 5, 5);
    		         // Hier auch senden		         
    		         try
    		         {
    		        	 oos.writeObject(me);
    		         }
    		         catch ( Exception ex )
    		         {
    		        	 System.out.println( ex.getMessage() );
    		         }
    		       }
    		       public void mouseMoved( MouseEvent me ) {}
    		      });
    		    }
    		   public void paintComponent(Graphics g)
    		   {
    		     super.paintComponent(g);
    		     g.fillOval( xa, ya, 5, 5);
    		   }
    		 }
    	 }
    

    jetzt der client:

    package ownSocketsT;
    
    	/**
    	002  * InEinFensterZeichnen.java
    	003  * Erzeugt einfaches Swing-Fenster
    	004  * in das gezeichnet werden kann.
    	005  * @author paff
    	006  * @version 1.0
    	007  */
    	 import javax.swing.*;
    
    	 import java.awt.*;
    	 import java.awt.event.*;
    	 import java.io.BufferedInputStream;
    	 import java.io.ObjectInputStream;
    	 import java.net.Socket;
    	 import java.net.UnknownHostException;
    	 import java.util.Date;
    	 import javax.swing.event.EventListenerList;
    	 import java.awt.Robot;
    
    	 //Die Klasse BlackBoardClient erweitert die Klasse JFrame.
    	 public class BlackBoardClient extends JFrame
    	 {
    		 static Socket socket;
    		 static ObjectInputStream ois;
    		 static int x;
    		 static int y;
    
    	   //Konstruktor der Klasse BlackBoardClient
    	   public BlackBoardClient() {
    
    	     //Konstruktor der Superklasse wird aufgerufen.
    	     super("Malen mit der Maus...");
    
    	     //Objekt der Klasse Zeichenflaeche wird erzeugt.
    	     Zeichenflaeche label = new Zeichenflaeche();	     
    
    	     //Inhaltsbereich wird abgefragt und Zeichenfläche eingefügt.
    	     Container contentPane = getContentPane();
    	     contentPane.add(label);
    
    	     WindowListener listener = new WindowAdapter()
    	     {
    	 	      public void windowClosing(WindowEvent e)
    	 	      {
    	 	        System.exit(0);
    	 	      }
    	     };
    
    	    this.addWindowListener(listener);
    	 	this.setSize(300, 200);
    	    this.setVisible(true);
    	   }
    
    	   public static void main(String[] args) 
    	   {
    		   BlackBoardClient jframe = new BlackBoardClient();
    			try 
    			{
    				socket = new Socket ("localhost" , 6666 );
    			    new ObjectInputStream (new BufferedInputStream ( socket . getInputStream ()));
    			    while( true)
    			    {
    
    			    	Object o = ois. readObject ();
    			    	MouseEvent me = (MouseEvent) o;
    			    	x = me.getX();
    			    	y = me.getY();
    
    	    		    	jframe.repaint();					    	System.out.println( me );
    			    }
    
    				//socket.close();
    			} 
    			catch ( UnknownHostException e) 
    			{
    				System . err. println (" Host  nicht gefunden");
    			}
    			catch ( Exception ex)
    			{
    
    			}
    	   }
    
    	   class Zeichenflaeche extends JLabel 
    		 {
    		   int xa = 0;
    		   int ya = 0;		   
    		   public void paintComponent(Graphics g)
    		   {
    		     super.paintComponent(g);
    		     xa = x;
    	         ya = y;
    		     g.fillOval( xa, ya, 5, 5);
    		   }
    		 }
    	 }
    


  • Danke fürs bearbeiten...weiß jemand Rat?



  • Ok habs selber gefunden ois muss natürlich als Referenz des Streams zugewiesen werden 🤡

    Leider kann ich jetzt immer nur den einem Punkt folgen der Rest wird wieder gelöscht, wird ja alles repainted...wie würde mann das denn anders machen? Sorry bin nicht ganz so fit in der Oberflächenprogrammierung



  • Im repaint() musst du sämtliche Komponenten neu zeichnen. Heißt für dich: Du merkst dir alle Elemente in einem Container ala:

    // Interface
    public interface Paintable
    {
        public void paintMe (final Graphics g);
    }
    
    // Implementierungen für alle möglihcen Aktionen die du via Sockets reinkriegen könntest (also zB Linie zeichnen, etc.):
    public class PaintLine implements Paintable
    {
        public void paintMe (final Graphics g)
        {
            g.drawLine(...);
        }
    }
    
    // Container + repaint:
    Container<Paintable> paintables = new LinkedList<Paintable>();
    
    ...
    
    public void repaint (final Graphics g)
    {
        for(Paintable p : paintables)
            p.paint(g);
    }
    

    MfG SideWinder



  • Wie wär's mit RMI?
    Definier dir mal schöne interfaces client und serverseitig. Unter der Haube läuft eh alles über TCP. Und du brauchst dir keine eigene proprietäre Formate für die serialisierung der events zu basteln. Bleibst einfach auf der höheren ebene.


Anmelden zum Antworten