Rebex SSH Shell
SSH shell, tunneling, telnet, ANSI terminal emulation library for .NET
Download 30-day free trial Buy from $699More .NET libraries
-
Rebex SFTP
SFTP client
-
Rebex SSH Pack
SSH Shell + SFTP + SSH server
-
Rebex Total Pack
All Rebex .NET libraries together
Back to feature list...
File Transfer (SFTP, YMODEM)
On this page:
Rebex SSH Shell supports a legacy file transfer protocol called YMODEM. It makes it possible to transfer files between the remote host (server) and the client using a terminal session. It is (and always has been) far from perfect - we recommend to only use it when there are no other alternatives. A typical scenario in which YMODEM is useful involves a connection over a serial cable or a modem, where more advanced file transfer protocols that run over TCP are not available.
However, in most cases, prefer one of the alternatives such as:
Sharing SSH session with SFTP
SFTP is the preferred file transfer protocol for use with SSH - it stands for "SSH File Transfer Protocol". It's realiable and more efficiant and it can share a single connection with with SSH. See SSH session sharing for details.
Terminal-based file transfers basics
Terminal-based file transfers using YMODEM are performed using the FileTransfers
object,
accessible as a property of ITerminal
interface (implemented by TerminalControl
and VirtualTerminal
classes).
It's also available on Scripting
object.
Getting FileTransfers
from Scripting
object
// get FileTransfers object for a Scripting object
var scripting = ssh.StartScripting();
FileTransfers transfers = scripting.Terminal.Transfers;
' get FileTransfers object from scripting
Dim scripting = ssh.StartScripting()
Dim transfers As FileTransfers = scripting.Terminal.Transfers
Getting FileTransfers
from VirtualTerminal
object
// get FileTransfers object for a VirtualTerminal object
VirtualTerminal terminal = ssh.StartVirtualTerminal();
FileTransfers transfers = terminal.Transfers;
' get FileTransfers object from VirtualTerminal
Dim terminal As VirtualTerminal = ssh.StartVirtualTerminal()
Dim transfers As FileTransfers = terminal.Transfers
Getting FileTransfers
from TerminalControl
object
By default, TerminalControl
uses automatic data processing mode,
which is not compatible with terminal-based file transfers. It is necessary to disable
automatic data processing before using the TerminalControl
object.
// disable automatic processing on the TerminalControl object
// (added to a Form using Visual Studio designer)
this.Terminal.SetDataProcessingMode(DataProcessingMode.None);
// get FileTransfers object fora TerminalControl object
FileTransfers transfers = this.Terminal.Transfers;
// use the FileTransfers object
// ...
// enable automatic processing
this.Terminal.SetDataProcessingMode(DataProcessingMode.Automatic);
' disable automatic processing of the TerminalControl object
' (that was added to the Form using Visual Studio designer)
Me.Terminal.SetDataProcessingMode(DataProcessingMode.None)
' get FileTransfers object from TerminalControl
Dim transfers As FileTransfers = Me.Terminal.Transfers
' use the FileTransfers object
' ...
' enable automatic processing
Me.Terminal.SetDataProcessingMode(DataProcessingMode.Automatic)
Receiving files
To receive a file, an YMODEM sender process has to be invoked at the remote host. On Linux, this functionality is provided by the lrzsz package's sb command.
Receiving files involves three steps:
- Issue command at the server to begin YMODEM sender process.
- Process error or initial messages such as "No such command" or "Ready to send".
- Start YMODEM receiver by calling
FileTransfers.StartReceiver()
method.
Example of complete file receiving routine:
// start scripting
var scripting = ssh.StartScripting();
// detect shell prompt
scripting.DetectPrompt();
// start YMODEM sender process
scripting.SendCommand("sb FILE_NAME");
// alternatively, use YMODEM-1k by adding "-k" option
//scripting.SendCommand("sb -k FILE_NAME");
// receive all messages sent by the sender process
// (in our scenario there is no message on success -> wait 3sec for error messages)
string response = scripting.ReadUntil(ScriptEvent.AnyText, ScriptEvent.Delay(3000));
if (!string.IsNullOrWhiteSpace(response))
{
// we received a text -> read whole response to prompt
response += scripting.ReadUntilPrompt();
throw new Exception("An unexpected response received: " + response);
}
// alternatively, use YMODEM-g
//scripting.Terminal.Transfers.EnableStreaming = true;
// start YMODEM receiver
using (var receiver = scripting.Terminal.Transfers.StartReceiver())
{
// receive all files
while (receiver.ReadNext())
{
// print some info about the current file
Console.WriteLine(receiver.FileName);
Console.WriteLine(receiver.Length);
Console.WriteLine(receiver.LastWriteTime);
// save the file
string file = Path.Combine(@"C:\data", receiver.FileName);
receiver.Receive(file);
}
}
// some YMODEM implementations are unreliable - send CTRL+C to request new prompt
scripting.Send(ConsoleKey.C, ConsoleModifiers.Control);
// wait for prompt before sending any additional commands
scripting.WaitFor(ScriptEvent.Prompt);
' start scripting
Dim scripting = ssh.StartScripting()
' detect shell prompt
scripting.DetectPrompt()
' start YMODEM sender process
scripting.SendCommand("sb FILE_NAME")
' alternatively, use YMODEM-1k by adding "-k" option
'scripting.SendCommand("sb -k FILE_NAME");
' receive all messages sent by the sender process
' (in our scenario there is no message on success -> wait 3sec for error messages)
Dim response As String = scripting.ReadUntil(ScriptEvent.AnyText, ScriptEvent.Delay(3000))
If Not String.IsNullOrWhiteSpace(response) Then
' we received a text -> read whole response to prompt
response &= scripting.ReadUntilPrompt()
Throw New Exception("An unexpected response received: " & response)
End If
' alternatively, use YMODEM-g
'scripting.Terminal.Transfers.EnableStreaming = true;
' start YMODEM receiver
Using receiver = scripting.Terminal.Transfers.StartReceiver()
' receive all files
While receiver.ReadNext()
' print some info about the current file
Console.WriteLine(receiver.FileName)
Console.WriteLine(receiver.Length)
Console.WriteLine(receiver.LastWriteTime)
' save the file
Dim file As String = Path.Combine("C:\data", receiver.FileName)
receiver.Receive(file)
End While
End Using
' some YMODEM implementations are unreliable - send CTRL+C to request New prompt
scripting.Send(ConsoleKey.C, ConsoleModifiers.Control)
' wait for prompt before sending any additional commands
scripting.WaitFor(ScriptEvent.Prompt)
In this sample, no initial message is expected. The sample code below shows how to handle a non-empty initial message.
Sending files
To send a file, YMODEM receiver process has to be invoked at the remote host (server). For UNIX it is available using for example lrzsz package, command rb.
Sending files is done at three steps:
- Issue command at the server to begin YMODEM receiver process.
- Process error or initial message, for example "No such command." or "Waiting to receive." message.
- Start YMODEM receiver by calling
FileTransfers.StartSender()
method.
Example of complete file sending routine
// start scripting
var scripting = ssh.StartScripting();
// wait for prompt
scripting.DetectPrompt();
// start YMODEM receiver process
scripting.SendCommand("rb");
// receive all messages sent by the receiver process
// (in our scenario, the message is "waiting to receive." -> wait at most 5sec)
string expected = "waiting to receive.";
var match = scripting.WaitFor(expected, ScriptEvent.Delay(5000));
if (!match.IsEventMatched(expected))
throw new Exception("An unexpected response received: " + scripting.ReceivedData);
// alternatively, use YMODEM-1k
//scripting.Terminal.Transfers.BlockSize = FileTransferBlockSize.OneKilobyte;
// start YMODEM sender
using (var sender = scripting.Terminal.Transfers.StartSender())
{
// send some files
foreach (var file in Directory.GetFiles(@"C:\data"))
{
sender.Send(file);
}
// inform the receiver process that we are done
sender.Finish();
}
// some YMODEM implementations are unreliable - send CTRL+C to request new prompt
scripting.Send(ConsoleKey.C, ConsoleModifiers.Control);
// wait for prompt before sending any additional commands
scripting.WaitFor(ScriptEvent.Prompt);
' start scripting
Dim scripting = ssh.StartScripting()
' wait for prompt
scripting.DetectPrompt()
' start YMODEM receiver process
scripting.SendCommand("rb")
' receive all messages sent by the receiver process
' (in our scenario, the message is "waiting to receive." -> wait at most 5sec)
Dim expected As String = "waiting to receive."
Dim match = scripting.WaitFor(expected, ScriptEvent.Delay(5000))
If Not match.IsEventMatched(expected) Then
Throw New Exception("An unexpected response received: " + scripting.ReceivedData)
End If
' alternatively, use YMODEM-1k
'scripting.Terminal.Transfers.BlockSize = FileTransferBlockSize.OneKilobyte;
' start YMODEM sender
Using sender = scripting.Terminal.Transfers.StartSender()
' send some files
For Each file In Directory.GetFiles("C:\data")
sender.Send(file)
Next
' inform the receiver process that we are done
sender.Finish()
End Using
' some YMODEM implementations are unreliable - send CTRL+C to request New prompt
scripting.Send(ConsoleKey.C, ConsoleModifiers.Control)
' wait for prompt before sending any additional commands
scripting.WaitFor(ScriptEvent.Prompt)
A non-empty initial message is expected in this example. The sample code above shows how to handle an empty initial message.
TransferProgressChanged event
Register a FileTransfers.TransferProgressChanged
event handler to get informed about transfer progress:
terminal.Transfers.TransferProgressChanged += (s, e) =>
{
switch (e.State)
{
case FileTransferProgressState.FileTransferring:
Console.WriteLine("Starting transfer of file '{0}'.", e.FileName);
break;
case FileTransferProgressState.DataBlockTransferred:
Console.WriteLine(" * data transferred: {1:F}% {2}B of '{0}'.",
e.FileName, e.ProgressPercentage, e.BytesTransferred);
break;
case FileTransferProgressState.FileTransferred:
Console.WriteLine("File transferred '{0}'.", e.FileName);
break;
case FileTransferProgressState.TransferCompleted:
Console.WriteLine("Transfer completed.");
break;
}
};
AddHandler terminal.Transfers.TransferProgressChanged,
Sub(s, e)
Select Case e.State
Case FileTransferProgressState.FileTransferring
Console.WriteLine("Starting transfer of file '{0}'.", e.FileName)
Exit Select
Case FileTransferProgressState.DataBlockTransferred
Console.WriteLine(" * data transferred: {1:F}% {2}B of '{0}'.", e.FileName, e.ProgressPercentage, e.BytesTransferred)
Exit Select
Case FileTransferProgressState.FileTransferred
Console.WriteLine("File transferred '{0}'.", e.FileName)
Exit Select
Case FileTransferProgressState.TransferCompleted
Console.WriteLine("Transfer completed.")
Exit Select
End Select
End Sub
Back to feature list...