InputStreamReader

beyoNd

Mitglied
Hallo, :)

leider find ich nix zu diesem Thema... :(
vll hat ja einer von euch den richtigen Suchbegriff oder einen Lösungsvorschlag für mich:)

hier teile vom Code.. müsste sich selbsterklären :)
Code:
read  = new BufferedReader (   new InputStreamReader (   sock.getInputStream( )   )   );
while(    (  temp = read.readLine ( )  ) != null   )
{
System.out.println( temp );
}

mein Problem:
wenn der Server keine Daten mehr sendet wartet der BufferedReader trozdem solange bis wieder etwas gesendet wird... aber der Server sendet mir aber erst wieder eine Antwort wenn ich ihm einem Befehl gesendet hab
--> da er ja nicht mehr aus der Schleife rauskommt kann ich ja keinen Befehl mehr senden... :(

aber ich muss aber halt die Schleife bilden damit ich alle Zeilen vom Server bekomm, oder nicht ?! Wisst ihr vll was ich da tun kann?! Oder hat jemand von euch auch mal mit so einem Problem rumgeärgert ?

lg Haiko
 
Zuletzt bearbeitet:
das ist eines der einfachsten dinge in der server-client kommunikation
lässt sich sehr einfach realisieren

wenn du deine app / dein applet "startest" erstelle in main 2 threads ... einer der daten vom server empfängt *also was du hier gepostet hast* und der andere der wiederum daten zum server sendet ...
du solltest das auf jeden fall mit 3 klassen lösen *main , empfangs-thread , sende-thread*
in der main-klasse hast du getter und setter methoden die mindestens protected haben sollten *wenn nicht im package dann definitiv public*
die beiden thread-klassen sollte einen konstruktor erhalten nach dem folgenden aufbau
Java:
public class EmpfangsThread extends Thread
{
MainClass mainClass;
public EmpfangsThread(MainClass mainClass)
{
this.mainClass=mainClass;
}
[...]
}
und eine initialisierung nach dem motto
Java:
[...]
EmpfangsThread eT=new EmpfangsThread(this);
eT.start();
[...]
nun kannst du in einem thread ganz locker in der while-loop bleiben und mit dem anderen daten zum server schicken ...
die verarbeitung der daten die vom server kommen müssten dann innerhalb der while-loop erfolgen
also so z.B.
Java:
while(...)
{
[...]
if(line.startsWith("--COM")) //überprüfung ob der server eine normale nachricht oder ein spezielles kommando sendet
{
[...]
}
[...]
}
wenn du nun rechen-intensive dinge damit veranstalten willst würde ich dir empfehlen diese dann in einem weiteren thread der aus der while-loop herraus gestartet wird zu erledigen damit das einlesen der daten vom server nicht unnötig blockiert wird


ich hoffe ich konnte dir damit schon mal etwas weiter helfen
wie gesagt ... dieses problem ist eigentlich eines der einfachsten und wird in jedem buch was sich mit server-client-kommunikation befasst ziemlich früh diskutiert
 
Hallo Spike :)

erstmal danke für die schnelle Antwort :)

Hab gerade erst Zeit gefunden zum Antworten...

also ich habe mir deinen Tipp zu Herzen genommen und versucht... leider wenn ich jetzt andauernd die Server Antworten auslesen lasse bekomme ich IMMER :( eine NullpointerException :(

was mache ich falsch?!

lg Haiko
 
ah .. ich wittere den leisen verdacht das ich weis WO deine NPE geworfen wird
wenn du mit einem BufferedReader in einer while hängst *sagen wir while((String line=in.readLine)!=null)* liest der BR solange zeilen-weise strings ein und beginnt die while von vorne bis der stream geclosed wird und damit die schleife auf grund einer exception abgebrochen wird *desshalb IN der while NIEMALS den try-catch setzen ... sondern immer AUßEN drum ... damit im fehler-fall abgebrochen wird und nicht auch noch das abbrechen fehlschlägt *welch schlechter wort-witz**
wenn nun aber grad keine daten vom server vorliegen läuft der BR ins leere und erzeugt einen leeren string ... im schlimmsten fall sogar ein null-object *was bei dir scheinbar i-wie passiert*
mein genereller aufbau solcher kommunikations-lopps sieht UNGEFÄHR so aus *pseudo-code*:
Java:
String line="";
try
{
	while((line=in.readLine())!=null)
	{
		if(!line.equals(""))
		{
			//code
		}
	}
}
catch(Exception e) { e.printStackTrace(); }
durch das if wird geprüft ob line != "" ist ... also das zumindest irgendwas in line stehen muss bevor damit gearbeitet wird ...
so wie ich dein problem verstehe passiert es dir nämlich an genau dieser stelle das line == "" ist und du dann versuchst darauf etwas anzuwenden was NULL als ergebnis hat und das du dann mit diesem NULL weiter arbeiten willst ... worauf berechtigt eine NPE geworfen wird ...
ich denke und hoffe ich habe dein problem getroffen ...
wenn nich musst du uns wirklich mal die entsprechende stelle posten ...

was auch noch wichtig wäre um z.B. chat-system zu realisieren ...
um clients nicht damit abzuwürgen sie mit abermilliarden CONNECTION-ERROR - zeilen zu zu spammen sollte im CATCH-block der AUßERHALB des while-loops ist entsprechend auf verbindung-abstürze reagiert werden

gleiches was ich eben alles auf CLIENTen bezogen habe gilt genau so auch für den server ... denn sonst wird dein server schnell mit ein paar dutzend ghost-connections einen fatal-error in der VM erzeugen die darauf hin einfach aussteigt
 
PseudoCode
Java:
public void run(){
			try{
				BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
				PrintWriter out = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
				
				String q = "";
				
				while((q = in.readLine()) != null){
					if (q.length() == 0) break;
				//	System.out.println(q);

					//code 
				}
			
			//	System.out.println("Verbindung wird beendet");
				out.close();
				in.close();
				client.close();
			//	System.out.println("Verbindung ist beendet");
			}
			catch(IOException e){
			
			}
			
		}

könnte so klappen?
 
ähm ... NEIN ... das wird so nicht den gewünschten effekt haben
ich glaube du solltest meinen anderen post noch mal lesen
nach dem was du da geschrieben hast stehen wir wieder an der selben stelle wie beim anfänglichen problem ...
der thread hängt beim einlesen der daten fest ... > DEADLOCK
mal davon abgesehen das das BREAK auch noch völlig deplatziert ist ...
wenn keine daten vorhanden sind brichst du die while damit ab und beendest die verbindung > einlesen von daten nicht möglich


ich seh schon ... ich muss euch hier mal mit n bissl code versorgen
also dann ... *anmerkung : das ist jetzt hier völlig frei geschrieben und NICHT getestet ... sollte aber soweit stimmen*
es wird hier nicht auf exception-behandlung eingegangen sondern der funktionstüchtigkeitshalber mit throws Exception an die VM delegiert

main-class > verbindungs-aufbau und delegation an die threads
Java:
import java.io.*;
import java.net.*;
public class app
{
	public static void main(String[] args) throws Exception
	{
		new app();
	}
	public app() throws Exception
	{
		Socket sock=new Socket(IP, PORT);
		BufferedReader in=new BufferedReader(new InputStreamReader(sock.getInputStream()));
		PrintStream out=new PrintStream(sock.getOutputStream());
		MsgSender msgs=new MsgSender(out);
		(new InThread(this, in, msgs)).start();
	}
}

InThread-class
Java:
import java.io.*;
import java.net.*;
class InThread extends Thread
{
	app a;
	BufferedReader in;
	MsgSender msgs;
	public InThread(app a, BufferedReader in, MsgSender msgs)
	{
		this.a=a;
		this.in=in;
		this.msgs=msgs;
	}
	public void run()
	{
		try
		{
			String l="";
			while((l=in.readLine())!=null)
			{
				if(!l.equals(""))
				{
					if(l.startsWith("--COM"))
					{
						//behandlung von commandos
					}
					if(l.startsWith("--MSG"))
					{
						//behandlung von normalen nachrichten
						//bsp zum senden
						msgs.SendMsg("request_file");
					}
					//usw
				}
			}
		}
		catch(Exception) { e.printStackTrace(); }
	}
}

MsgSender-class
Java:
import java.io.*;
import java.net.*;
class MsgSender
{
	PrintStream in;
	public MsgSender(PrintStream in)
	{
		this.in=in;
	}
	public void SendMsg(String l) throws Exception
	{
		out.println(l);
	}
}

wie gesagt ... das is jetzt alles nur so ausm stehgreif zusammen gezimmert ...
den MsgSender sollte man noch synchronized machen wenn dies wirklich erforderlich is ...
zur not auch wie gesagt in n thread packen und darin die arbeit erledigen lassen ...
das is ja auch alles nur pseudo-code und so auch NOCH nicht wirklich einsetzbar ...
und für n einfachen chat würde noch das GUI fehlen ... aber das ist ja hier nicht das thema oder ?

um dir wirklich mit code zu helfen müsstest du eig nur schreiben was du damit vorhast ...
dann könnte man mal so das rohgerüst zusammen zimmern

ACHTUNG : die variante mit BufferedReader / PrintStream ist wirklich nur für das senden von reinen plain-TEXT-daten ... binär-daten wie z.B. dateien oder verschlüsselte daten werden hier durch die umsetzung des entsprechenden zeichensatzes verstümmelt / zerstört ...
hier muss man dierekt die In/Out-streams der verbindung verwenden
 
Hey Spike, danke erstmal!

also, momentan sende ich einen FTP-Befehl an den Server und lasse mir alles ausgeben was von dem Server zurück kommt...

Java:
    public synchronized void cd(String ServerPath) throws FTPException, IOException
    {
        cmd("CWD "+ ServerPath, 250);
    }

    public synchronized Boolean cmd(String cmd, int StatusCode) throws IOException, FTPException
    {
        System.out.println("Send ->        "+  cmd);

        if(sendCmd(cmd) && getRespone(StatusCode))
            return true;
        else if (getFromFtp.startsWith("500 "))
        {
            System.out.println("CMD not supported");
        }
        
        return false;
    }

    private synchronized Boolean sendCmd(String cmd) throws FTPException
    {
        if(sock == null)
        {
            throw new FTPException("not connected to any Server");
        }
    
        try
        {
            
            write.write(cmd + "\r\n");
            write.flush();
            System.out.println("--> "+ cmd);
            return true;
            
        }
        catch (Exception e)
        {
            sock = null;
            return false;    
        }
        
            
    }

    private synchronized Boolean getRespone(int StatusCode) throws IOException, FTPException
    {        
        
            getFromFtp = read.readLine();
            
        while( !Pattern.matches( "\\d\\d\\d\\s.*", getFromFtp ) )
        {    
            getFromFtp = read.readLine();
        }

            System.out.println("    <-- "+getFromFtp);
        
        if(!getFromFtp.startsWith(StatusCode+" "))
        {
            //throw new FTPException("Error: responsed Line from Server: "+ getFromFtp);
        }
                                
        return true;
    }

Nun will ich aber auch "unerwartete" Server Response abfangen wie "zeitlimitüberschritten" etc...

dafür brauche ich einen Thread, nur leider hab ich garkeine Ahnung von Threads, und die Tutorials die ich gefunden habe sind auch nicht gerade gut und hilfreich gewesen -.-






Die NPE habe ich bekommen als ich nur einen Thread zum dauerhaften auslesen der Respones benutzt habe...

Aber wie kann ich sonst dauerhaft alle Respones einlesen ?! die unerwartet sind?

lg beyoNd
 
also ohne mir jetzt den code zu ziehen ... in ne datei zu packen ... was drum rum zu basteln ... und dann zu versuchen es zu compilen ... kann ich dir jetzt schon sagen das das was du uns hier gepostet hast definitiv zu einem compile-error führen wird

dessweiteren ist auch die logik hinter diesem code auch nachem dritten mal durchlesen sehr schwer zu verstehen ... und selbst dann wundere ich mich noch das da was anderes steht als das ding eigentlich machen soll

ich denke du hast hier die falsche herangehensweise ...
erstmal solltest du dir überlegen : was genau willst du machen
dann : wie könnte man es implementieren ... pseudo-code hilft hier immer ein stück weiter ...
folgend : überprüfung der logik : gehe die einzelnen schritte einfach noch mal logisch durch und überprüfe ob das auch wirklich genau so läuft wie es gedacht ist ...
schlussendlich : implementierung und testen

grad was FTP angeht ... da braucht man einiges an wissen mehr als die bloße socket-kommunikation über den steuer-kanal ... vor allem muss man die unterschiede zwischen active und passive kennen und diese umsetzen können ...

aber ich will dich jetzt nicht entmutigen und versuch dir mal so gut ich kann zu helfen

das erste was mir aufgefallen ist waren diese schrecklichen THROWS-konstrukte
wenn das ganze nur zum testen in der entwicklung ist kannst du ruhig throws Exception oder sogar throws Throwable verwenden um einfach mal alles an die VM zu deligieren
später im produktiven einsatz solltest du dann solche throws-konstrukte vermeiden *außer wo es wirklich sinn macht* und in den methoden selbst mit try-catch-finaly - blöcken darauf reagieren ...
dabei ist die reihen folge zu beachten ...

java.lang.Throwable

ist die basis-klasse ... wenn du dir nicht sicher bist was geworfen wird einfach Throwable nehmen

java.lang.Throwable hat zwei dierekte sub-klassen

java.lang.Error und java.lang.Exception

beide für unterschiedliche aufgabenbereiche ...
das meiste wird sicher über Exception laufen ...
Error hingegen beinhaltet sub-klassen die laut api nicht in einem catch-block oder einer throws-clause abgefangen werden sollten ...
Error und seine sub-klassen stellen abnormale probleme der gesamten VM dar und sind speziell dafür gedacht die VM bewusst dadurch "abzuschießen"
Exception hingegen wird verwendet wenn bewusst gefordert wird das auftretende fehler abgefangen und behandelt werden
und jetzt kommt die hirarchie der Exception's ins spiel ...
sehen wir uns mal deinen code an ...
einmal steht FTPException VOR der IOException ... und einmal dahinter ...
welches ist nun aber richtig ... das hängt vorallem von der implementation der FTPException ab
da diese in java selbst nicht spezifiziert ist muss man nun kuggn welche die super-klasse von FTPException ist ...
die meisten FTPException-implementationen die mir google liefert sind dierekt von Exception abgeleitet und stehen damit auf der selben stufe wie IOException ...
auch ableitungen von RuntimeException stehen effektiv mit IOException auf der selben stufe ...
hier ist also die reihenfolge wirklich egal ...
wenn FTPException aber nun von IOException *oder einer der sub-klassen* abgeleitet ist muss definitiv ERST die FTPException abgefangen werden und DANN erst die IOException ...
nehmen wir mal als beispiele eine SocketException
diese wird wie folgt abgeleitet
>java.lang.Object
>>java.lang.Throwable
>>>java.lang.Exception
>>>>java.io.IOException
>>>>>java.net.SocketException

damit müsst also in einem try-catch block

Java:
try
{
//code
}
catch(SocketException se) { }
catch(IOException ioe) { }
catch(Exception e) { }

sowas hier kommen um die Exceptions ihrer hirarchie-stufe umgekehrt abzufangen ...
wenn du es andersrum schreiben würdest würdest du auch bei einer konkreten SocketException nie in den se-block kommen die IOException oder Exception drüber stehen und es abfangen würden wenn diese ÜBER der SocketException stehen würden ... also darauf achten um richtig zu catchen

was jetzt dein problem mit den Threads angeht

Threads sind dazu da um mehrere teile deiner app parallel laufen zu lassen ... also "quasi"-gleichzeitig
erklärung : sehen wir uns mal eine normale java-app an ...
du wirst erkennen das die app einer festgelegten reihenfolge folgt und immer nur genau eins nach dem anderen macht
um dem auf moderenen multi-process und multi-thread system endgegenzuwirken und diese fähigkeit nutzbar zu machen wurden Threads erfunden ...
damit kannst du mehrere teile gleichzeitig laufen lassen ...
z.B. die verarbeitung von daten und gleichzeitiges warten auf neue daten vom und zusätzlich grad welche zum server hinschicken ...
durch mehrere threads lassen sicher aber auch leicht DEADLOCKS erzeugen ... vorallem wenn die app so aufgebaut ist das es keinen theoretischen fehlerfall gibt und darauf verzichtet wurde die threads zu synchronisieren
DEADLOCKS sind meist logik-fehler ...
sie entstehen dadurch das sich mehrere Threads (in)dierekt gegenseitig blockieren
zum beispiel das ein thread auf daten wartet und der zweite *der eigentlich zum senden beauftragt wurde* nichts tut weil der erste ihm nicht sagt DAS er was tun soll und WAS er tun soll ...
allerdings ist das problem das der erste thread nichts macht ohne daten zu bekommen ... was wiederum nur ausgelöst wird wenn der zweite thread daten sendet ...
das ist einer der häufigsten DEADLOCKS ... gibt noch ne reihe anderer schöner beispiele

wenn du jetzt unvorhergesehende daten lesen willst ... also bei denen du nicht weist OB bzw WANN diese kommen ... baust du dir einfach einen thread in dem dauerhaft auf eingehende daten gewartet wird ...
um jetzt allerdings dem DEADLOCK vorzubeugen musst du diesen thread davon abhalten daten zu lesen wenn du gerade in einem anderen thread auf diese daten wartest ...
das tut man in der regel mit BOOL-variablien die dann geprüft werden ...
nach dem du die daten hast die du haben wolltest änderst du diesen bool-wert einfach wieder und der andere thread beginnt wieder mit seiner arbeit ...
dazu dürfte auch i-wo im netz pseudo-code rumfliegen

du siehst also ... das ganze ist garnicht so schwer wie du es dir gerade machst ...
und mit dem synchronized meinte ich eigentlich das man nur entsprechende getter / setter sinnvollerweise synchronized machen sollte ... aber halt nur da wo es notwendig ist ...
weil wenn du gleich die ganze app synchronized brauchst du keine threads mehr ...
 
Aber wenn ich einen Thread erzeuge der nur die Aufgabe hat:

Java:
             if( andereMethodeLiestGerade == true)
{

            getFromFtp = read.readLine();
            
        while( !Pattern.matches( "\\d\\d\\d\\s.*", getFromFtp ) )
        {    
            getFromFtp = read.readLine();
        }
}

bekomme ich ne NPE weil ja nichts vom Server kommt un der Thread sagt: "Moment ich brauch noch ein bissl ich soll noch gerade die Server Respones einlesen danach darfst du wieder Arbeiten", ensteht doch der DeadLock oder nicht?!

Tut mir leid aber ich hab ÜBERHAUPT keine ahnung von Threads :D ^^

lg beyoNd
 
Zurück