TScSSHShell.ExecuteCommand - Sleep(50)
TScSSHShell.ExecuteCommand - Sleep(50)
Hi,
we are using the SecureBridge Components TScSSHClient and TScSSHShell to communicate over SSH.
I was wondering about a call to 'Sleep(50)' in method TScSSHShell.ExecuteCommand, while reading the stream until it has become closed. Doing so turns out to be actually quite slow. I tried to reduce the waited time and ended up removing the call completely. The communication still worked as expected, but about 10 times faster (but I tested it in our LAN only yet to be honest).
Could you explain where this sleep(50) originates from or why it is required?
Thanks and best regards,
Daniel
we are using the SecureBridge Components TScSSHClient and TScSSHShell to communicate over SSH.
I was wondering about a call to 'Sleep(50)' in method TScSSHShell.ExecuteCommand, while reading the stream until it has become closed. Doing so turns out to be actually quite slow. I tried to reduce the waited time and ended up removing the call completely. The communication still worked as expected, but about 10 times faster (but I tested it in our LAN only yet to be honest).
Could you explain where this sleep(50) originates from or why it is required?
Thanks and best regards,
Daniel
Re: TScSSHShell.ExecuteCommand - Sleep(50)
Since often the shell slowly returns the result, our numerous studies have shown that to correctly retrieve the entire result, you should execute the specified sleep(50). If you have SecureBridge source code, you can delete this sleep.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
Hi,
thank you very much for the swift response.
Yes, we have the SecureBridge source code and tried to delete this sleep. That's where curiosity had us.
What we wonder is:
I would also be very grateful if you could share an example (like a part of one of your studies, a specific command to execute or a description of an environment to execute a command in or such), to enlighten the cause for this delay.
Best regards,
Daniel
Btw: Should you need any customer data to check whether we are eligible for support, please let me know (I would try to make contact via the customer portal then).
thank you very much for the swift response.
Yes, we have the SecureBridge source code and tried to delete this sleep. That's where curiosity had us.
What we wonder is:
- The data from the stream is read until the stream has become closed. As SSH (if not for mesh) works on TCP, we would consider the stream to be reliable and should thus not be closed before the TCP connection signals all data to be transferred.
- If it's actually to wait for 'something it does not yet know how long it will take', then why using 50ms? And what could that be? A single command could easily take longer than 50ms to return anything, as well as network latency.
- If it's just meant to reduce the load on the thread, we really would consider to reduce or remove this delay, at least for high performance/local connections, where latency <<50ms is not uncommon.
I would also be very grateful if you could share an example (like a part of one of your studies, a specific command to execute or a description of an environment to execute a command in or such), to enlighten the cause for this delay.
Best regards,
Daniel
Btw: Should you need any customer data to check whether we are eligible for support, please let me know (I would try to make contact via the customer portal then).
Re: TScSSHShell.ExecuteCommand - Sleep(50)
In general, your comments are correct. The delay discussed was introduced to improve performance when working with slow SSH servers in a slow network. We will investigate this behavior and try to optimize it taking into account the actual data.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
I have the same issue here.
Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`. That turns things much more slow...
If I use `NonBlocking+OnAsyncReceive`, I can receive all data. However, I don't know when it will finish and that is a problem to me: how to know if I can release my thread?
I would like to know if it is possible:
1. do not call sleep
2. do not call `SetConnected` on `ExecuteCommand`
Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`? For example: if I use `ExecuteCommand` and type `ls`, I can see the results - the same for NonBlocking. However, if I type `cd ..` I just see data in NonBlocking mode.
best regards
Marcos Douglas
Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`. That turns things much more slow...
If I use `NonBlocking+OnAsyncReceive`, I can receive all data. However, I don't know when it will finish and that is a problem to me: how to know if I can release my thread?
I would like to know if it is possible:
1. do not call sleep
2. do not call `SetConnected` on `ExecuteCommand`
Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`? For example: if I use `ExecuteCommand` and type `ls`, I can see the results - the same for NonBlocking. However, if I type `cd ..` I just see data in NonBlocking mode.
best regards
Marcos Douglas
Re: TScSSHShell.ExecuteCommand - Sleep(50)
Hello Marcos,
> Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`.
and
> Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`?
That's due to the specification of the SSH protocol. See https://www.ietf.org/rfc/rfc4254.txt Chapter 6.5 (Starting a Shell or Command). The 'exec' message is specified to run a command and return all results till the command terminates (in some way), closing the connection. This is used in ExecuteCommand.
ExecuteCommand has the advantage that you don't have to deal with the shell and have a real indicator on the termination. On the downside, the specification requires a separate connection to do so, resulting in quite some overhead if you want to execute many commands.
> However, if I type `cd ..` I just see data in NonBlocking mode.
'CD ..' has no output on its own, it just changes the current directory of the current shell. Using ExecuteCommand acts similar to running each single command in its own shell. As such 'ExecuteCommand('cd..')' won't do anything ...
The 'NonBlocking' approach opens a shell (the 'shell' message in the specification), which keeps track of its state (like the current directory). As such, it can handle more than just one command and would also return some data.
It has the disadvantage, that it only transfers text. As such, you would have to think of a method to determine the termination of a single command on your own.
> Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`.
and
> Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`?
That's due to the specification of the SSH protocol. See https://www.ietf.org/rfc/rfc4254.txt Chapter 6.5 (Starting a Shell or Command). The 'exec' message is specified to run a command and return all results till the command terminates (in some way), closing the connection. This is used in ExecuteCommand.
ExecuteCommand has the advantage that you don't have to deal with the shell and have a real indicator on the termination. On the downside, the specification requires a separate connection to do so, resulting in quite some overhead if you want to execute many commands.
> However, if I type `cd ..` I just see data in NonBlocking mode.
'CD ..' has no output on its own, it just changes the current directory of the current shell. Using ExecuteCommand acts similar to running each single command in its own shell. As such 'ExecuteCommand('cd..')' won't do anything ...
The 'NonBlocking' approach opens a shell (the 'shell' message in the specification), which keeps track of its state (like the current directory). As such, it can handle more than just one command and would also return some data.
It has the disadvantage, that it only transfers text. As such, you would have to think of a method to determine the termination of a single command on your own.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
DanielT comments are correct.
The shell channel particularity is that after command executing, using the TScSSHShell.ExecuteCommand method, the channel will be closed by the server after receiving a command execution result, regardless of a value of the TScSSHShell.NonBlocking property and a client cannot affect it.
You can connect to the server and send commands to the server using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods, after their execution the channel is not closed: https://www.devart.com/sbridge/docs/tsc ... string.htm, https://www.devart.com/sbridge/docs/tsc ... buffer.htm
The shell channel particularity is that after command executing, using the TScSSHShell.ExecuteCommand method, the channel will be closed by the server after receiving a command execution result, regardless of a value of the TScSSHShell.NonBlocking property and a client cannot affect it.
You can connect to the server and send commands to the server using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods, after their execution the channel is not closed: https://www.devart.com/sbridge/docs/tsc ... string.htm, https://www.devart.com/sbridge/docs/tsc ... buffer.htm
Re: TScSSHShell.ExecuteCommand - Sleep(50)
Hi @DanielT
So, shell, program or subsystem. `ExecuteCommand` is using 'program' in that case, right?
At the end of RFC says: "The server SHOULD NOT halt the execution of the protocol stack when starting a shell or a program. All input and output from these SHOULD be redirected to the channel or to the encrypted tunnel."
In my understanding is the opposite, ie, the client should not close the connection in 'shell' or 'program' mode.
The overhead is because 'sleep()' calls and closing connection...
--
Hi @ViktorV
The 'sleep()' calls I can just remove, replace by events (callbacks) or just decrease the number. But I would like to understand the disadvantages, if I remove `SetConnected(False)` and related code.
Thanks.
Maybe I didn't understand. The RFC says: "The program can be a shell, an application program, or a subsystem with a host-independent name".That's due to the specification of the SSH protocol. See https://www.ietf.org/rfc/rfc4254.txt Chapter 6.5 (Starting a Shell or Command). The 'exec' message is specified to run a command and return all results till the command terminates (in some way), closing the connection. This is used in ExecuteCommand.
So, shell, program or subsystem. `ExecuteCommand` is using 'program' in that case, right?
At the end of RFC says: "The server SHOULD NOT halt the execution of the protocol stack when starting a shell or a program. All input and output from these SHOULD be redirected to the channel or to the encrypted tunnel."
In my understanding is the opposite, ie, the client should not close the connection in 'shell' or 'program' mode.
Yes, this is want I need.ExecuteCommand has the advantage that you don't have to deal with the shell and have a real indicator on the termination.
Separate connection or not was encapsulated into the component - we might not think about it.On the downside, the specification requires a separate connection to do so, resulting in quite some overhead if you want to execute many commands.
The overhead is because 'sleep()' calls and closing connection...
I know that. However, I would like to show for users what is happening. If you try 'NonBlocking' , you will see that 'cd ..' brings data on 'OnAsyncReceive'. IMHO, both should have the same behavior... but this is not the main issue.'CD ..' has no output on its own, it just changes the current directory of the current shell.
--
Hi @ViktorV
I understood the behavior by design. However, I haven't understood why might be like that. What the advantages closing connection first?The shell channel particularity is that after command executing, using the TScSSHShell.ExecuteCommand method, the channel will be closed by the server after receiving a command execution result, regardless of a value of the TScSSHShell.NonBlocking property and a client cannot affect it.
Yes. The problem is that I don't know when all data has finished. That's why I would like to use `ExecuteCommand`, which uses 'ReadAllData' protected method - not public, not available.Нou can connect to the server and send commands to the server using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods, after their execution the channel is not closed:
The 'sleep()' calls I can just remove, replace by events (callbacks) or just decrease the number. But I would like to understand the disadvantages, if I remove `SetConnected(False)` and related code.
Thanks.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
When calling the TScSSHShell.ExecuteCommand method, the 'exec' request type is sent, which, according to the RFC, starts the execution of the given command only. This type of the request does not imply the execution of other commands, so after executing the command and sending the entire result to the client, the server closes the channel, which is fully consistent with the documentation. This behavior is typical for all known SSH servers and we cannot influence this.
We noted earlier that the SSH protocol allows using only 2 request types for your task - 'shell' or 'exec'. Each of these requests has its pros and cons. Therefore, you should choose a more optimal path for you. Once again, we advise you to pay attention to the 'shell' request and abandon the 'exec'. The 'shell' request is executed when calling the TScSSHShell.Connect method and commands are sent using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods.Yes. The problem is that I don't know when all data has finished. That's why I would like to use `ExecuteCommand`, which uses 'ReadAllData' protected method - not public, not available.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
@ViktorV
I'm already using `shell`, which has the best performance. However, how the app can know when the stream is done?
For example: imagine that we need to save each command typed into a row on a grid. Each row should have the server, command, and output. As the output (could) come on pieces, the program might include more than one row for the same command.
In your opinion, which would be the best approach to know the end of the stream? It shouldn't be hard-coded, though.
I'm already using `shell`, which has the best performance. However, how the app can know when the stream is done?
For example: imagine that we need to save each command typed into a row on a grid. Each row should have the server, command, and output. As the output (could) come on pieces, the program might include more than one row for the same command.
In your opinion, which would be the best approach to know the end of the stream? It shouldn't be hard-coded, though.
Re: TScSSHShell.ExecuteCommand - Sleep(50)
We cannot give you any advice because the SSH protocol does not send the size of the data resulting from the end of the operation. Also, the shell does not return any standardized characters that define the end of the result.