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...