2009-09-20 25 views
11

Semplicemente ho cercato di implementare ciò che BufferedStreamReader fa in Java. Ho un flusso di socket aperto e voglio solo leggerlo in modo orientato alla linea - riga per riga.C# - StreamReader.ReadLine non funziona correttamente!

Ho il seguente codice server.

while (continueProcess) 
     { 
      try 
      { 
       StreamReader reader = new StreamReader(Socket.GetStream(), Encoding.UTF8); 
       string command = reader.ReadLine(); 
       if (command == null) 
        break; 

       OnClientExecute(command); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     } 

E il seguente client-code:

TcpClient tcpClient = new TcpClient(); 
     try 
     { 
      tcpClient.Connect("localhost", serverPort); 
      StreamWriter writer = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8); 
      writer.AutoFlush = true; 
      writer.WriteLine("login>user,pass"); 
      writer.WriteLine("print>param1,param2,param3"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.ToString()); 
     } 
     finally 
     { 
      tcpClient.Close(); 
     } 

Il server legge solo la prima riga (login>user,pass) e poi ReadLine restituisce null!

Qual è il modo più semplice per ottenere questo lettore orientato alla linea come in Java BufferedStreamReader? : s

+1

prega, smaltire gli oggetti qui (lo StreamReader e StreamWriter). Altrimenti potresti avere problemi imprevisti. Basta mettere un blocco usando intorno a loro (come in uso (StreamWriter writer = ...) {}), e starai bene – configurator

+0

Non che fosse pertinente alla domanda - solo un suggerimento. – configurator

+0

ottimo;) grazie – Aleyna

risposta

12

Una tipica linea-reader è qualcosa di simile:

using(StreamReader reader = new StreamReader(Socket.GetStream(), Encoding.UTF8)) { 
    string line; 
    while((line = reader.ReadLine()) != null) { 
     // do something with line 
    } 
} 

(notare che il using per assicurarci di Dispose() anche se otteniamo un errore, e il ciclo)

Se si vuole, si potrebbe abstract questo (separazione degli interessi), con un blocco iteratore:

static IEnumerable<string> ReadLines(Stream source, Encoding encoding) { 
    using(StreamReader reader = new StreamReader(source, encoding)) { 
     string line; 
     while((line = reader.ReadLine()) != null) { 
      yield return line; 
     } 
    } 
} 

(di notare che ho trasferito questo in una funzione e ha rimosso il "fare qualcosa", sosti ng con "ritorno rendimento", che crea un iteratore (un pigramente iterato, non-buffering macchina a stati)

Ci sarebbe poi consumare questo nel modo più semplice:

foreach(string line in ReadLines(Socket.GetStream(), Encoding.UTF8)) { 
    // do something with line 
} 

Ora il nostro codice di elaborazione non lo fa è necessario preoccuparsi di come leggere righe - semplicemente dato una sequenza di linee, fare qualcosa con loro.

Si noti che lo using (Dispose()) si applica anche a TcpClient; dovresti prendere l'abitudine di controllare per IDisposable; per esempio (ancora compreso il vostro errore-registrazione):

using(TcpClient tcpClient = new TcpClient()) { 
    try { 
     tcpClient.Connect("localhost", serverPort); 
     StreamWriter writer = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8); 
     writer.AutoFlush = true; 
     writer.WriteLine("login>user,pass"); 
     writer.WriteLine("print>param1,param2,param3"); 
    } catch (Exception ex) { 
     Console.Error.WriteLine(ex.ToString()); 
    } 
} 
+0

Quando uso StreamReader per leggere dal socket, ho trovato che il programma client si sta bloccando, impiegando una quantità infinita di tempo nel metodo ReadLine() e alla fine non riesce a leggere. –

+0

@MasudRahman che di solito significa: il server non sta inviando una riga completa (cioè stai chiedendo di aspettare qualcosa che il server non ha un motivo per inviarti), o il server ha dimenticato di svuotare un buffer di output. È possibile * aggiungere un timeout di lettura, ma alla fine non è possibile inviare dati al server. Ovviamente puoi eseguire la lettura e il buffering, ma ciò cambia la natura del problema: può quindi essere il tuo lavoro decidere che una linea completa non è stata inviata dopo un certo periodo di tempo. –

5

Il tempo nel codice del server è impostato per leggere solo una riga per connessione. Ne avrai bisogno un altro mentre cerchi di leggere tutte le linee inviate. Penso che una volta che lo stream è configurato dal lato client, invierà tutti i dati. Quindi sul lato server, il tuo stream sta effettivamente leggendo solo una riga da quel particolare stream.

+0

dopo aver modificato il mio server e il codice client come segue server: usando (lettore di StreamReader = new StreamReader (Socket.GetStream(), Encoding.UTF8)) { while (continueProcess) .... cliente : ... Thread.Sleep (10000); writer.WriteLine ("print> test, one, two"); Ho inserito Thread.Sleep (10000) nel mio codice client e il server ha iniziato a generare un'eccezione. Il socket del client sarà aperto fino alla chiusura del client e poiché il client invierà i dati per tutto il suo ciclo di vita sembra che questo codice genererà un errore. Non la pensi così? – Aleyna

+0

Senza vedere quale sia il nuovo codice o nuova eccezione, non sono sicuro di quale potrebbe essere il problema. – LJM

0

provato questo e ha ottenuto

Il tipo o dello spazio dei nomi il nome 'flusso' non è stato trovato (le manca un un riferimento all'assembly direttiva using o? Impossibile trovare il nome dello spazio dei nomi 'StreamReader' (manca una direttiva using o un riferimento all'assembly?) Impossibile trovare il nome dello spazio dei nomi 'StreamReader' (manca una direttiva using o un assembly riferimento?) 'System.Net.Sockets.Socket' non contiene una definizione per 'GetStream'

+1

pls fare riferimento a http://msdn.microsoft.com/en-us/library/system.io.stream.aspx – Aleyna

0
public string READS() 
    { 
     byte[] buf = new byte[CLI.Available];//set buffer 
     CLI.Receive(buf);//read bytes from stream 
     string line = UTF8Encoding.UTF8.GetString(buf);//get string from bytes 
     return line;//return string from bytes 
    } 
    public void WRITES(string text) 
    { 
     byte[] buf = UTF8Encoding.UTF8.GetBytes(text);//get bytes of text 
     CLI.Send(buf);//send bytes 
    } 

CLI è una presa. per alcuni rezona la classe TcpClient non funziona più sul mio pc, ma la classe Socket funziona perfettamente.

UTF-8 è il filamento di codifica StreamReader/Writer