How to return data line by line - WeOnlyDo Discussion board

How to return data line by line (wodSSH / wodSSH.NET)

by Ernesto Cullen, Wednesday, November 19, 2014, 12:26 (3418 days ago)

Hi
I have to process a command on a remote linux machine that will return a lot of text (think 'ls -alR /'). If I use ssh.Execute it returns all data as a string which is killing my memory, and in fact I need to process it line by line so I want to return the data that way. I tried several variations on following code, all gave me some text and then block completely until timeout. What am I doing wrong?

Thanks in advance,

Ernesto



  ...
  String partialData = String.Empty;

  ssh.DataReceivedEvent += (sender, args) =>
  {
     ssh.Timeout = 0;
     while (true)
     {
       try
       {
         var tempString = ((SSH) sender).PeekLine();
         ((SSH)sender).Receive(tempString.Length);
         if (partialData.Length > 0)
         {
           var s = partialData + tempString;
           action(s);
           partialData = String.Empty;
         }
         else
         {
           action(tempString);
         }
       }
       catch (Exception ex)
       {
         //receive whats left of the buffer, waiting for the next batch
         var partialString = ((SSH) sender).Receive();
         partialData += partialString;
         break;
       }
     }
     ssh.Timeout = timeout;
   };

  ssh.Connect(hostname, port);
  ...

Action<String> action is a delegate that will be called to send each line.

How to return data line by line

by Jasmine, Wednesday, November 19, 2014, 13:48 (3418 days ago) @ Ernesto Cullen

Hi Ernesto.

I didn't check the code very carefully, since I have to ask first: why didn't you use ReceiveLine method in the first place?

ReceiveLine method helpfile

Perhaps that would help?

Jasmine.

How to return data line by line

by Ernesto Cullen, Wednesday, November 19, 2014, 14:39 (3418 days ago) @ Jasmine

Because ReceiveLine will block if there is no complete line in buffer, while PeekLine raises an exception. If I don't get the exception, I know there is a line in buffer and so I can use ReceiveLine (in later tests I replaced with Receive(length) but it is the same). But even so, I still got blocked sometimes.
Maybe the receive buffer is modified while I am extracting the data? if so, how can I prevent this to happening?

How to return data line by line

by Jasmine, Wednesday, November 19, 2014, 15:12 (3418 days ago) @ Ernesto Cullen

Hi Ernesto.

You should make a choice to use events or use Blocking = True mode, don't use both.

If you use events, then DataReceived event will fire when there's new data arrived, which you can consume. Since you're using Blocking = False in that case, ReceiveLine will also return immediately even if no data is waiting, so this is what you need.

If you use Blocking = True, don't use events, but use ReceiveLine in some loop.

Which option suits you better?

Jasmine.

How to return data line by line

by Ernesto Cullen, Wednesday, November 19, 2014, 19:04 (3418 days ago) @ Jasmine

ok, I will try with both modes to see which one is better for our app. In blocking mode, how do you define the loop? In the code below I use DataReady property, but in the help it says explicitly that this is not reliable. What should I use then?
Could you write a small example using the non blocking mode?


...
var linesReceived = 0;
ssh.Command = "ls -alR /";
try
{
    ssh.Connect(hostname, port);
    while (true)
    {
        var tempLine = ssh.ReceiveLine();
        Console.WriteLine("{0} {1}", ++linesReceived, tempLine);
        if (ssh.DataReady == 0)
            break;
    }
}
catch (Exception ex)
{
    DebugMessage(String.Format("Connection exception {0}: {1}", ex.GetType(), ex.Message));
    throw;
}

The exception code needs more work, at least I should capture the 'None found' exception (is it an Exception instance or some ENoneFoundException or something like that?) to cover the case when the command output does not include EOL at the end.

thanks

Ernesto

How to return data line by line

by Jasmine, Wednesday, November 19, 2014, 19:26 (3418 days ago) @ Ernesto Cullen

Hi Ernesto.

When to break out of loop depends on you. You should check if State == Connected - to make sure connection didn't drop while waiting for data to arrive. Besides that, get out of loop when you're personally ready, when you have received data you have expected.

Jasmine.

How to return data line by line

by Ernesto Cullen, Wednesday, November 19, 2014, 19:36 (3418 days ago) @ Jasmine

ok so what is the best way to check if there is still data? I want to receive all data sent. After the command is executed, the connection is closed? Maybe I could use that

How to return data line by line

by Jasmine, Wednesday, November 19, 2014, 21:29 (3417 days ago) @ Ernesto Cullen

Hi Ernesto.

I'm not sure what you're doing, so I can't say how to receive all data you send. Receive should return it. How to know it's end of what you have sent, and you're receiving data you expect to receive as a result of your command? Depends on the command itself. You should know what you have sent and what to expect back, and what is the 'separator' for those, perhaps just a CR LF sequence?

Jasmine.