11

Simply I have been trying to implement what BufferedStreamReader does in Java. I have a socket stream open and just want to read it in a line-oriented fashion - line by line.

I have the following server-code.

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());
            }
        }

And the following 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();
        }

The server reads only the very first line (login>user,pass) and then ReadLine returns null!

What's the easiest way of achieving this line-oriented reader as it is in Java's BufferedStreamReader? :s

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aleyna
  • 1,857
  • 4
  • 20
  • 27
  • 1
    Please, dispose of your objects here (the StreamReader and StreamWriter). Otherwise you may get unexpected problems. Simply put a using block around them (as in using (StreamWriter writer = ...) { } ), and you'll be ok – configurator Sep 20 '09 at 04:15
  • Not that it was relevant to the question - just a suggestion. – configurator Sep 20 '09 at 04:16

4 Answers4

17

A typical line-reader is something like:

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

(note the using to ensure we Dispose() it even if we get an error, and the loop)

If you want, you could abstract this (separation of concerns) with an iterator block:

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;
        }
    }
}

(note we've moved this into a function and removed the "do something", replacing it with "yield return", which creates an iterator (a lazily iterated, non-buffering state machine)

We would then consume this as simply as:

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

Now our processing code doesn't need to worry about how to read lines - simply given a sequence of lines, do something with them.

Note that the using (Dispose()) applies to TcpClient too; you should make a habit of checking for IDisposable; for example (still including your error-logging):

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());
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • When I use StreamReader for reading from the socket, I found that the client program is freezing, taking infinite amount of time at ReadLine() method, and finally failing to read. – Masud Rahman Sep 17 '15 at 04:36
  • @MasudRahman that usually means either: the server isn't sending a complete line (i.e. you're asking it to wait for something that the server doesn't have a reason to send you), or the server has forgotten to flush an output buffer. You *can* add a read timeout, but ultimately it can't make the server send data. You can of course do the reading and buffering yourself, but this just changes the nature of the problem - it can then be your job to decide that a complete line hasn't been sent after some period of time. – Marc Gravell Sep 17 '15 at 09:21
  • The fault in the original code (since it's not really explained anywhere, is that you are recreating the streamreader each time around the loop, which looses the rest of the buffer. – Chris Pugmire Jun 07 '23 at 01:12
6

The while in your server code is setup to only read one line per connection. You'll need another while within the try to read all of the lines being sent. I think once that stream is setup on the client side, it is going to send all of the data. Then on the server side, your stream is effectively only reading one line from that particular stream.

LJM
  • 6,284
  • 7
  • 28
  • 30
  • After altering my server and client code as follows server: using (StreamReader reader = new StreamReader(Socket.GetStream(), Encoding.UTF8)) { while (continueProcess) .... client: ... Thread.Sleep(10000); writer.WriteLine("print>test,one,two"); I inserted Thread.Sleep(10000) to my client code and server started throwing exception. The client socket will be open till client exits and since client will send data throughout its lifecycle seems like this code will throw error. Don't you think so? – Aleyna Sep 20 '09 at 04:49
  • Without seeing what the new code or new exception is, I'm not sure what the problem might be. – LJM Sep 20 '09 at 04:58
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 is a socket. for some rezone the TcpClient class doesn't work right on my pc any more, but the Socket class works just fine.

UTF-8 is the stranded StreamReader / Writer Encoding

-2

Tried this and got

The type or namespace name 'Stream' could not be found (are you missing a using directive or an assembly reference?) The type or namespace name 'StreamReader' could not be found (are you missing a using directive or an assembly reference?) The type or namespace name 'StreamReader' could not be found (are you missing a using directive or an assembly reference?) 'System.Net.Sockets.Socket' does not contain a definition for 'GetStream'