Java Server/Client

Gruß Thomas!

Grand Admiral Special
Mitglied seit
27.03.2008
Beiträge
2.027
Renomée
118
Standort
Bayreuth
  • Docking@Home
Ich habe hier eine Methode, die etwas Sendet:

PHP:
public void send()
     {
         String send = "";
         if(xUnit2 != null)
         {
              send = (xUnitX + "_" + xUnitY + "_" + yUnit.getPositionX() + "_" + yUnit.getPositionY() + "_" + xUnit2.getPositionX() + "_" + xUnit2.getPositionY() + "_" + zUnitX + "_" + zUnitY);
         }
         else
         {
             send = (xUnitX + "_" + xUnitY + "_" + yUnit.getPositionX() + "_" + yUnit.getPositionY() + "_" + -1 + "_" + -1 + "_" + -1 + "_" + -1);   
         }
         try
         {
             Socket socket = new Socket(ip,port);
             PrintWriter printWriter = new PrintWriter( new OutputStreamWriter(socket.getOutputStream()));
             printWriter.print(send);
             printWriter.flush();
         }
         catch(Exception e)
         {
             
          }
     }

Und eine die etwas empfängt:

PHP:
public void read()
     {
         try
         {
            ServerSocket serverSocket = new ServerSocket(port);
            Socket socket = serverSocket.accept();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( socket.getInputStream()));
            char[] buffer = new char[200];
            int chars = bufferedReader.read(buffer, 0, 200);
            String read = new String(buffer, 0, chars);
            String write[] = read.split("_");
            if(write.length != 8)
            {
                read();
            }
            int writeInt[] = new int[8];
            for(int i = 0; i < 8; i++)
            {
                writeInt[i] = Integer.parseInt(write[i]);
            }
            main.move(writeInt[0],writeInt[1],writeInt[2],writeInt[3]);
            if((writeInt[4] != -1) && (writeInt[5] != -1) && (writeInt[6] != -1) && (writeInt[7] != -1))
            {
                main.attack(writeInt[4],writeInt[5],writeInt[6],writeInt[7]);
            }
            else
            {
                main.abortAttack();
            }
        }
        catch(ArrayIndexOutOfBoundsException ex)
        {
            System.out.println("ARRAY KAPUTT");
        }
        catch(IOException io)
        {
            System.out.println("IO-Fehler");
        }
        catch(Exception e)
        {
            System.out.println("FEHLER");
        }
     }

Und die funktionieren miteinander schon ziemlich gut auf einem PC (ansprechen per 127.0.0.1, Port ist in der Klasse definiert mit 7500). Aber sobald ich den Code über LAN ausprobiere streikt er, d.h. die Read Methode bleibt einfach bei serverSocket.accept() stehen oder so...

Ich vermute ja, dass die send() methode zu schnell für read() ist und einfach weitermacht, ohne dass etwas empfangen wurde, aber wie kann ich das beheben?
 
ich hab den code noch nicht ganz verinnerlicht, aber mir fällt auf, dass du beim senden alles in einem ty-catch-block machst, aber der catch-block leer ist. wenn jetzt das anlegen des sockets oder dem datenversand scheitert, dann bekommst du nichts davon mit.
 
Den hab ich auch noch nicht komplett fertig geschrieben...

Aber nun zurück zum Problem :)
 
wenn der server im accept hängt, ist es naheliegend, dass bei ihm keine verbindung ankommt. mögliche ursachen können z.b. ne firewall, rigide mandatory access control systeme (selinux, grsecurity o.ä.) oder eben ein problem auf client-seite sein. solange du die gefangene exception einfach unausgewerte wegwirfst, wirst du nicht merken, wenn der client probleme hat beim aufbau der verbindung. da mindeste wäre ne kurze konsolenausgabe um zu merken, dass das prog ne exception geworfen hat. am besten sowas wie e.printStackTrace().
send() für read() zu schnell? unwahrscheinlich, da die verbindung per tcp erfolgt. tcp stellt die vollständige und fehlerfreie übertragung der daten sicher. würdest du udp benutzen, müsstest du all dies selber von hand implementieren.

edit:
nach was, schon mal die beiden progamme durchn debugger geschickt und nachgesehen, wo es tatsächlich hakt?
 
Naja, ich benutze eine Entwicklungsumgebung (BlueJ), die mir anzeigt, wenn der Rechner noch rechnet. Und das macht die Read Methode ja immer (Programm bricht nicht ab).

Kann ich das mit dem accept() auch weglassen und die IP manuell eintragen? Ich hab das ja vorrangig zum warten genommen, bis eine Eingabe kommt...

Naja mal schauen, das mach ich morgen oder so, weil heute ist erst mal lernen angesagt für Klausur :)
 
ok, read() läuft also weiter, und was macht send()?
 
send() sendet nur kurz was und hört dann auf, ohne überprüft zu haben, ob was gesendet wurde.

Kann das sein, dass der Fehler wegen der Rekursion bei fehlerhaften Datenpaketen kommt?
PHP:
            if(write.length != 8)
            {
                read();
            }

Dass dann sozusagen der String nicht komplett eingelesen wird, einfach weiter gemacht wird und dann die Methode neugestartet wird? (Kann ich mir jetzt eigentlich nicht vorstellen, könnte aber sein oder nicht... Ich kann das jetzt aber leider nicht überprüfen, da ich in der Schule sitze und das Projekt nicht da habe.)

send() spuckt außerdem keine Fehler aus...
 
wenn write.length != 8 sein sollte, und du in die rekursion gehst, wird ein neuer serversocket erstellt, da bereits einer auf diesem port besteht, knallts. dabei gibts ne fehlermeldung wegen der gefangenen exception, das "zweite" read() wird beendet und das "erste" read() fortgesetzt, da die rekursion beendet ist. in der folgenden for-schleife würde es im falle von write.length < 8 ebenfalls knallen, da i bis 7 läuft. ist write.length jedoch > 8, klappt es, aber in dem falle ist auch was in die hose gegangen, da nur exakt 8 elemente im array sein dürfen.

kurz gesagt, deine behandlung des falls write.length != 8 funktioniert so nicht.

wenn du mehrfach verbindungen mit dem serversocket annehmen möchtest, musst du lediglich mehrfach accept() aufrufen, z.b. in einer schleife. sollen die verbindungen parallel laufen, musst du mit threads arbeiten, die sich um jeweils eine der verbindungen kümmern, da solange dein code eine verbindung behandelt, keine weiteren verbindungen angenommen werden können.

um den fehler einzugrenzen könntest du z.b. die zu sendenden und die empfangenen daten und deren länge auf der konsole ausgeben. auch ein debugger ist in solchen fällen hilfreich.

btw: was meinst du mit deinem ersten satz? dein geposteter code hat nichts zur überprüfung drin. *noahnung* diese überprüfung würde allerdings erfordern, dass die gegenseite ne passende nachricht zurückschickt, was du ebenfalls implementieren müsstest. das wäre aber overkill. der netzwerkstack sorgt dafür, dass die daten, die du auf die reise schickst, ankommen. geht dabei etwas schief, kommt ne exception. bleibt diese aus, ist das datenpaket zumindest beim zielrechner angekommen, ob das dort lauschende programm etwas damit anfangen kann, steht auf einem anderen blatt.

am ende solltest du die streams und sockets noch schließen, wenn du mit ihnen durch bist.

noch ein tip:
aussagekräftigere namen wären nett und vermeiden missverständnisse. also z.b. ne eigene methode send() und die variable send sind nicht so praktisch. das gleiche gilt für read() und read, char und chars, sowie main und main(). in bluej kommt man wohl ohne main() aus, hab ich gehört, in richtigen programmen, egal, ob assembler, c, c++, java und afaik auch c# kommt man nicht ohne main-methode aus. ohne main-methode kann du dort kein programm starten. lediglich libs könntest du schreiben, aber eben nicht ausführen.

wenn mir noch was einfallen sollte, melde ich mich noch mal. im augenblick fällt mir gerade nichts mehr ein
 
Ich weiß, dass man nicht ohne main() Methode auskommt.

Und ich glaube, ich Mache die Sockets als Variable in die Klasse, dann knallts weniger :) Danke schonmal dafür.

Und das mit dem Konsole ausgeben hab ich auch schon gemacht, bloß rausgenommen hier :P
 
ok, das hättest du vielleicht dazu sagen können ;)
 
Zurück
Oben Unten