Toon posts:

[java] BufferedReader probleem

Pagina: 1
Acties:

Verwijderd

Topicstarter
Dit programma bestaat uit 2 onderdelen: een server en een client.

Doelstelling: De client moet de tekst die de server verstuurt, op het scherm weergeven. Soms verstuurt de server slechts 1 zin, echter het kan ook voorkomen dat de server een aantal zinnen, gescheiden met \n (newline) achter elkaar verstuurt. Als alle tekst van de server op het scherm staat, mag de gebruiker input geven. De tekst die de gebruiker invoert, wordt naar de server gestuurd. Als reactie op de invoer v.d. gebruiker, kan het zijn dat de server weer tekst wil versturen, en begint het proces van voor af aan.

Nu heb ik de volgende stukjes code:
Java:
1
2
3
audioSocket = new Socket("localhost", 4444);
out = new PrintWriter(audioSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(audioSocket.getInputStream()));

Java:
1
2
3
4
5
6
7
8
9
10
11
while ((fromServer = in.readLine()) != null) {
   System.out.println("Server: " + fromServer);
   if (fromServer.equals("Bye."))
        break;

   fromUser = stdIn.readLine();
      if (fromUser != null) {
      System.out.println("Client: " + fromUser);
      out.println(fromUser);
   }
}


Dit heeft als resultaat dat de client 1 regel input van de server leest. Daarna mag de gebruiker 1 regel tekst naar de server sturen, waarna het proces weer opnieuw begint. Zodra de server het woord bye stuurt, wordt de loop beëindigd.

Dit werkt prima, maar de client leest maar 1 regel input van de server, waarna de gebruiker onmiddelijk om invoer wordt gevraagd. Zodra de server nu meerdere regels tekst na elkaar verstuurt, gaat het mis. Ik moet de client dus zien duidelijk te maken, dat hij alle input van de server op het scherm zet, en dus niet slechts 1 regel alvorens de gebruiker om invoer wordt gevraagd.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while ((fromServer = in.readLine()) != null) {
            while ((fromServer = in.readLine()) != null) {
                System.out.println("Server: " + fromServer);
            }

            System.out.println("Server: " + fromServer);
            if (fromServer.equals("Bye."))
                break;

            fromUser = stdIn.readLine();
        if (fromUser != null) {
                System.out.println("Client: " + fromUser);
                out.println(fromUser);
       }
        }

Bovenstaande code leest wel keurig alle input van de server, maar raakt dan in een oneindige loop, waardoor de gebruiker niet meer om input wordt gevraagd. Het feit dat hij in een oneindige loop raakt, vind ik vreemd, vanwege de volgende tekst in de java api:
Readline() returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Ik zou verwachten dat als de server geen tekst meer verzendt, het einde van de stream is bereikt, en de loop dus zou moeten stoppen.

Kan er iemand mij vertellen hoe ik dit probleem kan oplossen?

[ Voor 7% gewijzigd door Verwijderd op 13-12-2005 18:24 ]


  • Nibble
  • Registratie: Juli 2001
  • Laatst online: 13-04 15:26
Vergeef me het feit dat ik niet meer compleet helder ben om 3:56 (ik ben ook zo met java bezig :P en het wil even hard lukken) ^^. Ik weet niet precies hoeveel controle je hebt over de serverside.
Maar zou je bijvoorbeeld alle text kunnen bufferen tot de server een "over" geeft om zo de client te laten weten dat het bericht compleet is? Ik weet niet of het mogelijk is, maar het lijkt me wel, om bijvoorbeeld een javabean/collection/arraylist over te gooien en zo een soort atomaire actie te maken die alleen wordt getoond als hij compleet binnen is.

T is for TANK, and T is for TERROR ... and K is the K for KILLING in error.


  • bvp
  • Registratie: Maart 2005
  • Laatst online: 16-04 19:03

bvp

Op deze manier ga je wel uit de while loop en kun je na deze loop verder met het invoeren van de tekst aan de client-side:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FileReader fr;
  try {
    fr = new FileReader("C:/dev/temp/bin/classes/bla.txt");
    BufferedReader br = new BufferedReader(fr);
            
    String line = br.readLine();
    while (line != null) {
      System.out.println(line);
      line = br.readLine();
    }
  } 
  catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
  catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
  }


Uiteraard in die bufferedreader nog ff jouw outputstream gebruiken....

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Je kan [code=java] gebruiken om wat kleurtjes te geven.

Je tweede codevoorbeeld slaat de eerste regel over: je hebt effectief twee readLines achter elkaar (als je dat anders wilt, moet je regel 6 naar regel 2 verplaatsen). Wat nu gebeurt als er alleen een "Bye." terugkomt na een input, is dat "Bye." gelezen wordt, fromServer vervolgens met null gevuld wordt en de break dus niet meer uitgevoerd wordt.

Wie trösten wir uns, die Mörder aller Mörder?


  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 03:55

Nick_S

++?????++ Out of Cheese Error

En als je met een socket werkt, heb je ook geen einde van je stream.

Je zal een soort protocol moeten afspreken, bijvoorbeeld zoals HTTP met content-length gedaan heeft.

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Het is ook de vraag hoe de controle moet lopen. Kan je gebruiker altijd text invoeren of mag het alleen nadat de server wat verstuurd heeft.
Als de server bepaald wanneer de client wat mag sturen zul je daar iets voor in je protocol moeten opnemen. Bijvoorbeeld een aparte sequence die aangeeft dat de server op input wacht.

Als de client in principe altijd data kan sturen kun je beter of met meerdere threads gaan werken of met a-synchrone communicatie.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • bodiam
  • Registratie: December 2001
  • Laatst online: 31-12-2024
Verwijderd schreef op dinsdag 13 december 2005 @ 03:30:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while ((fromServer = in.readLine()) != null) {
            while ((fromServer = in.readLine()) != null) {
                System.out.println("Server: " + fromServer);
            }

            System.out.println("Server: " + fromServer);
            if (fromServer.equals("Bye."))
                break;

            fromUser = stdIn.readLine();
        if (fromUser != null) {
                System.out.println("Client: " + fromUser);
                out.println(fromUser);
       }
        }

Bovenstaande code leest wel keurig alle input van de server, maar raakt dan in een oneindige loop, waardoor de gebruiker niet meer om input wordt gevraagd. Het feit dat hij in een oneindige loop raakt, vind ik vreemd, vanwege de volgende tekst in de java api:
Hoi, je hebt 2 loopjes, waarbij beiden eigenlijk niet oneindig zouden moeten loopen. Hoe weet je dat je code in een oneindige loop komt? Omdat "System.out.println("Server: " + fromServer);" steeds wordt uitgevoerd? Wat staat er dan in de variabele 'fromServer'? Of is het wellicht zo dat hij niet loopt (looped?), maar meer blijft 'hangen'? Ik heb dat zelf wel eens gehad, omdat ik dan vergeten ben te controleren of de inputstream (ik weet zo uit mijn hoofd niet of dat ook bij BufferedReaders zo is) wel ready() is.

  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 03:55

Nick_S

++?????++ Out of Cheese Error

bodiam schreef op dinsdag 13 december 2005 @ 13:14:
[...]


Hoi, je hebt 2 loopjes, waarbij beiden eigenlijk niet oneindig zouden moeten loopen. Hoe weet je dat je code in een oneindige loop komt? Omdat "System.out.println("Server: " + fromServer);" steeds wordt uitgevoerd? Wat staat er dan in de variabele 'fromServer'? Of is het wellicht zo dat hij niet loopt (looped?), maar meer blijft 'hangen'? Ik heb dat zelf wel eens gehad, omdat ik dan vergeten ben te controleren of de inputstream (ik weet zo uit mijn hoofd niet of dat ook bij BufferedReaders zo is) wel ready() is.
Hij draait niet oneindig rondjes. Hij is aan het wachten op input van de server.

code:
1
while ((fromServer = in.readLine()) != null) {

in.readLine() is een zogeheten blocking call en zal dus pas returnen als er iets binnen is gekomen of de stream is gesloten. Je doet deze beide dingen niet, dus blijft hij wachten op input.

Zoals eerder gemeld, je zal een protocol moeten gaan vast stellen, zodat je weet hoe veel je binnen krijgt, of hoe lang je moet lezen.

Bijvoorbeeld:
code:
1
2
content-length=3
bla


De client of server weet nu, dat wat hij binnen krijgt altijd begint met een content-length header en dat er daarna in dit geval nog 3 tekens komen.

Bijvoorbeeld:
code:
1
2
3
4
5
lalala
bla
die bla
nog een regeltje
%%END_OF_MESSAGE%%


De client of server weet nu, dat hij moet blijven lezen, totdat hij een regel binnen krijgt, die gelijk is aan "%%END_OF_MESSAGE%%. (Let er in dat geval op, dat de String "%%END_OF_MESSAGE%%" niet in je bericht mag voorkomen.)

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


Verwijderd

Topicstarter
Nick_S schreef op dinsdag 13 december 2005 @ 13:37:
code:
1
while ((fromServer = in.readLine()) != null) {

in.readLine() is een zogeheten blocking call en zal dus pas returnen als er iets binnen is gekomen of de stream is gesloten. Je doet deze beide dingen niet, dus blijft hij wachten op input.
Gezien in.readLine() een blocking call is, en ik de stream niet afsluit, heeft de voorwaarde in deze while statement weinig nut. De variable fromServer wordt nooit null. Dit is dus net zoveel zeggen als
while (true){...}

Met jullie aanwijzingen heb ik het stukje code herschreven:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
while (true){
   boolean closeConnection=false;
   while (!closeConnection){

      fromServer = in.readLine();

      if (fromServer.equals("End_of_Message"))
        break;

      System.out.println("Server: " + fromServer);

      if(fromServer.equals("Bye"))
         closeConnection=true;
      }
      if (closeConnection)
         break;
      fromUser = stdIn.readLine();
      if (fromUser != null) {
         System.out.println("Client: " + fromUser);
         out.println(fromUser);
      }
}


Dit levert het gewenste resultaat _/-\o_

Verwijderd

Topicstarter
Het trucje om een datastreameinde aan te geven met de tekst End_of_Message wou ik ook bij mijn UDP server en client toepassen:

Client:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;
import java.net.*;
class UDPClient {
    public static void main(String args[]) throws Exception
    {
        DatagramSocket clientSocket = new DatagramSocket(5555);
        byte[] receiveData = new byte[100];

        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        clientSocket.receive(receivePacket);
        String audio = new String(receivePacket.getData());
        System.out.println("FROM SERVER:" + audio);
        while (!audio.equals("End_of_Message")){
            receivePacket = new DatagramPacket(receiveData, receiveData.length);
            clientSocket.receive(receivePacket);
            audio = new String(receivePacket.getData());
            System.out.println("FROM SERVER:" + audio);
        }
        clientSocket.close();
    }
}


Server:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.io.*;
import java.net.*;
class UDPServer {
   public static void main(String args[]) throws Exception
      {
         DatagramSocket serverSocket = new DatagramSocket(9876);
            byte[] sendData = new byte[100];
            while(true)
               {
                  InetAddress IPAddress =InetAddress.getByName("127.0.0.1");
                    //Send audiofile
                    for(int i=0; i< 1; i++){
                        String audio ="Stuur Random Text";
                        sendData = audio.getBytes();
                        DatagramPacket sendPacket =new DatagramPacket(sendData,sendData.                            length,IPAddress, 5555);
                        serverSocket.send(sendPacket);
                    }
                    //Send stream end command
                    String audio ="End_of_Messages";
                    sendData = audio.getBytes();
                    DatagramPacket sendPacket =new DatagramPacket(sendData,sendData.                            length,IPAddress, 5555);
                    serverSocket.send(sendPacket);
               }
      }
}


Er zijn echter enkele problemen met de server waardoor dit niet helemaal werkt. De server moet x aantal keer een willekeurige tekst over UDP verzenden. De client moet blijven luisteren totdat de tekst End_of_Message langs komt.

Probleem:
De server stopt de tekst in het datagram. De grote van dit datagram kan ik met de code byte[] sendData = new byte[100]; variëren. Dit datagram is echter groter dat de hoeveelheid tekst die ik wil versturen. Als de client dit datagram uitleest, krijgt hij niet alleen de tekst, maar ook de rest van het datagram te zien. Het resultaat is dat hij De tekst print, plus een aantal regels spaties. Gezien de tekst die ik verstuur niet van een vaste lengte is, moet ik dus op de een of andere manier de tekst van die witregels scheiden.
Als dit scheiden lukt, wordt ook voorkomen dat hij in een oneindige loop raakt, omdat hij nooit een match kan vinden voor End_of_Message. Er komt immers nog een stuk achter.

Verwijderd

Topicstarter
Probleem is opgelost. Met een mooie reguliere expressie kun je alle troep uit het datagram wegknippen:

Java:
1
2
3
4
5
6
7
8
9
public String Extractor(String audio){
    String pattern="(.*)(<EndOfLine>)";
    Pattern p=Pattern.compile(pattern);
    Matcher m=p.matcher(audio);
    
    m.find();
    audio=m.group(1);
        return audio;
}
Pagina: 1