Author Topic: SSH ChannelReadAndPoll, dont wait and exit when everything was recieved ?  (Read 408 times)

marhyno

  • Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Hi, I am having trouble tuning my application. I am trying to find best possible solution how to execute commands on device, wait for output and then disconnect. Problem is sometimes getting output takes about 15-20 seconds, therefore I used also ChannelReadAndPoll command. But I see that when I set up this command to have timeout 30 seconds, It waits also around 30 seconds when it already gets all the output which is time wasting.

How can I tune the application, so when it gets all the output or a specific line faster It can disconnect.

/*THIS IS THE SET OF COMMANDS I WANT TO RUN */

              success = end_device.ChannelSendString(channelNum, command, "ansi");

              if (success != true)
              {
                    result = "Execution of commands failed";
                    return Tuple.Create(false, result);
              }

              // Wait and fetch streaming output from Device
              var cmdOutput = end_device.ChannelReadAndPoll(channelNum, 30000);
              if (cmdOutput < 0)
              {
                    result = end_device.LastErrorText;
                    return Tuple.Create(false, result);
              }

              /* SEND END OF COMMANDS */
              success = end_device.ChannelSendEof(channelNum);
              if (success != true)
              {
                    result = "Execution of commands failed";
                    return Tuple.Create(false, result);
              }

              //  After recieving output close the channel:
              success = end_device.ChannelSendClose(channelNum);
              if (success != true)
              {
                    result = end_device.LastErrorText;
                    return Tuple.Create(false, result);
              }

              if (success)
              {
                    result += end_device.GetReceivedText(channelNum, "ansi");
                    return Tuple.Create(true, result);
              }

Chilkat

  • Administrator
  • Full Member
  • *****
  • Posts: 100
  • Karma: +6/-0
    • View Profile
I think you should be able to do things in this order:

  • Call ChannelSendString
  • Call ChannelSendEof
  • Call ChannelSendClose
  • Call ChannelReceiveToClose
  • Call GetReceivedText

The pollTimeoutMs argument pased to ChannelReadAndPoll is intended to be a small time duration.  It's a method where the intent it to read incoming data, and keep reading until data stops arriving.  The call will return when data stops arriving for the amount of time specified by pollTimeoutMs.  This means that any call to ChannelReadAndPoll will not return for at least pollTimeoutMs.  (It's a call good for certain situations, but not your particular situation..)

marhyno

  • Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
So you are saying I should not use the ChannelReadAndPoll method at all ? Honestly I dont believe this will work but I will give it a try. Just for you imagination I am pasting commands to cisco switches / routers. This works fine but the last command which tells the switch to save config has delay before it starts and also it takes some time during execution (displaying progress of saving to the disk). So it happens that sometimes I see just last command without the output or half of the output from the last command (e.g. progress till 58% of saving) because the sessions disconnects from the switch. Do you really think I should use it without this method ? Will I get any output from this ? Or how the application will know when it needs to disconnect ? I dont really understand the ChannelSendEof method (like when it is executed, or how it knows when it should be executed or like it will not interrupt exeuctions and getting outputs from many commands ?) So far, thanks for the suggestion :)
« Last Edit: March 07, 2018, 06:00:33 PM by marhyno »

marhyno

  • Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Unfortunately this doesnt work, I wont even fetch any output from the device. I commented out the ChannelReadAndPoll and added ChannelReceiveToClose. But this time I dont get any output.

/*THIS IS THE SET OF COMMANDS I WANT TO RUN */
            success = end_device.ChannelSendString(channelNum, command, "ansi");

            if (success != true)
            {
                result = "Execution of commands failed";
                return Tuple.Create(false, result);
            }

            // Wait and fetch streaming output from Device
            /*var cmdOutput = end_device.ChannelReadAndPoll(channelNum, 30000);
            if (cmdOutput < 0)
            {
                  result = end_device.LastErrorText;
                  return Tuple.Create(false, result);
            }*/

            /* SEND END OF COMMANDS */
            success = end_device.ChannelSendEof(channelNum);
            if (success != true)
            {
                result = "Execution of commands failed";
                return Tuple.Create(false, result);
            }

            //  After recieving output close the channel:
            success = end_device.ChannelSendClose(channelNum);
            if (success != true)
            {
                result = end_device.LastErrorText;
                return Tuple.Create(false, result);
            }

            //  After recieving output close the channel:
            success = end_device.ChannelReceiveToClose(channelNum);
            if (success != true)
            {
                result = end_device.LastErrorText;
                return Tuple.Create(false, result);
            }

            if (success)
            {
                result += end_device.GetReceivedText(channelNum, "ansi");
                return Tuple.Create(true, result);
            }

marhyno

  • Newbie
  • *
  • Posts: 4
  • Karma: +0/-0
    • View Profile
Okay, guys I have solved my problem once and for all. I used ChannelReceiveUntilMatch method and it works like a charm. Please mark it as solved, so this can help other people too.


/*THIS IS THE SET OF COMMANDS I WANT TO RUN */
            success = end_device.ChannelSendString(channelNum, command, "ansi");

            if (success != true)
            {
                result = "Execution of commands failed";
                return Tuple.Create(false, result);
            }

            success = end_device.ChannelReceiveUntilMatch(channelNum, hostname + "# exit", "ansi", false);
            if (success != true)
            {
                result = "Execution of commands failed";
                return Tuple.Create(false, result);
            }

            /* SEND END OF COMMANDS */
            success = end_device.ChannelSendEof(channelNum);
            if (success != true)
            {
                result = "Execution of commands failed";
                return Tuple.Create(false, result);
            }

            //  After recieving output close the channel:
            success = end_device.ChannelSendClose(channelNum);
            if (success != true)
            {
                result = end_device.LastErrorText;
                return Tuple.Create(false, result);
            }

            //  After recieving output close the channel:
            success = end_device.ChannelReceiveToClose(channelNum);
            if (success != true)
            {
                result = end_device.LastErrorText;
                return Tuple.Create(false, result);
            }

            if (success)
            {
                result += end_device.GetReceivedText(channelNum, "ansi");
                return Tuple.Create(true, result);
            }