Many users have asked about how to connect to DriveHQ's FTP server in their own software projects. In this message, we'd like to provide some general information about FTP first, followed with some C# source code.
DriveHQ offers FTP server hosting service. We support the regular FTP and FTPS protocols. One of the main advantages of our FTP service is: it is seamlessly integrated with our broad cloud IT services. Users can access their FTP files using web browser, mapped drive (WebDAV) or DriveHQ FileManager client software. They can also use our web-based Group Admin tool to create and manage FTP users (sub-users).
The regular FTP protocol is considered insecure as it transmits data without encryption. For strong SSL security, you can use FTPS (FTP over SSL/TLS). There are two methods of invoking SSL security:
Implicit: The FTP client directly connects to a special FTPS port number (default is 990);
Explicit (FTPES): The FTP client connects to the regular FTP port number 21, and then issues a command STARTTLS to upgrade the security.
DriveHQ's FTP server supports both FTPS and FTPES. Most FTP client applications support FTPS and FTPES, e.g. FileZilla, CuteFTP, WsFTP, SmartFTP, WinSCP and Fetch, etc.
There is another secure file transfer protocol named SFTP, which is often confused with "Secure FTP"; in fact, it means "SSH File Transfer Protocol", a completely different file transfer protocol. From security point of view, SSL/TLS and SSH are about the same. Clearly SSL/TLS is more popular than SSH. DriveHQ's FTP server does not support SFTP as we don't see a strong need for SFTP.
Active and Passive Mode FTP:
An FTP connection may include two TCP connections (channels), the command channel and the data channel. The command channel is used for sending FTP commands; the data channel is used for transferring large amount of data. Active Mode FTP requires the FTP server to connect back to the FTP client to establish the data connection. This is often considered insecure and is blocked by many firewalls/routers. Passive Mode FTP requires the FTP client to connect to the FTP server on a different port number. It is considered safe and rarely blocked. DriveHQ's FTP server supports both Active and Passive FTP. However, if your router / firewall or security software blocks Active FTP, then it won't work. It is interesting to note that most of new routers do support Active FTP.
Please note: Microsoft's command-line FTP client does not support Passive FTP. Almost all other FTP client programs support both Active and Passive FTP.
FTP and ProFTP
DriveHQ has two FTP sites, one is ftp.drivehq.com, which is accessible to all users; the other one is proftp.drivehq.com, which is available to paid members only (incl. sub-users of a paid group account). Because proftp.drivehq.com is only available to paid members, it does not support anonymous FTP. For more info about our FTP server hosting service, please visit:
http://www.drivehq.com/servicemanual.aspx#_Toc265186728
Sample FTP Client Source Code
The following C# source code is provided as is without any support. You can feel free to use it in your own software, or redistribute it. The sample code shows how to connect to our FTP server and execute FTP commands, such as LIST, GET and PUT; you can also see how to set it to use Passive FTP and SSL.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
/// <summary>
/// Copyright (c) 2003-2016, Drive Headquarters, Inc.
///
/// The FTP client sample code shows how to connect to DriveHQ's FTP server using C#.
/// You can use the code or re-distribute it for free. The code is provided AS IS without
/// any support or warranty. DriveHQ will not assume any liability from using the code.
/// </summary>
namespace FTPClientSample
{
class Program
{
static string ftpServer = "ftp.drivehq.com"; // you can also use proftp.drivehq.com if you have a paid account.
static string username = "YOUR_USERNAME"; // Your DriveHQ username
static string password = "YOUR_PASSWORD"; // Your DriveHQ password
static void Main(string[] args)
{
// List a folder on the ftp server
//List("/");
// Download a file from the FTP server
//DownloadFile("ServerFileName.jpg", @"c:\temp\ClientFileName.jpg");
// Upload a file to the FTP server
UploadFile(@"c:\temp\ClientFileName.jpg", "/temp/ServerFileName.jpg");
}
/// <summary>
/// Upload a file to the FTP server.
/// </summary>
/// <param name="srcFilePath">a local file path</param>
/// <param name="destFilePath">the path on the FTP server, such as /temp/filename</param>
/// <returns></returns>
public static bool UploadFile(string srcFilePath, string destFilePath = null)
{
if (String.IsNullOrWhiteSpace(srcFilePath))
throw new ArgumentNullException("Source FilePath.");
if (String.IsNullOrWhiteSpace(destFilePath))
destFilePath = Path.GetFileName(srcFilePath);
Uri serverUri = GetUri(destFilePath);
// the serverUri should start with the ftp:// scheme.
if (serverUri.Scheme != Uri.UriSchemeFtp)
return false;
FtpWebRequest request = CreateFtpRequest(serverUri, WebRequestMethods.Ftp.UploadFile);
// read file content into byte array
FileStream sourceStream = new FileStream(srcFilePath, FileMode.Open, FileAccess.Read);
byte[] fileContent = new byte[sourceStream.Length];
sourceStream.Read(fileContent, 0, fileContent.Length);
sourceStream.Close();
// send the file content to the FTP server
request.ContentLength = fileContent.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContent, 0, fileContent.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Response status: {0} - {1}", response.StatusCode, response.StatusDescription);
return true;
}
/// <summary>
/// Download srcFilePath on the FTP server to the destFilePath. If null, save to the current folder)
/// </summary>
/// <param name="srcFilePath"></param>
/// <param name="destFilePath"></param>
/// <returns></returns>
public static bool DownloadFile(string srcFilePath, string destFilePath = null)
{
if (String.IsNullOrWhiteSpace(srcFilePath))
throw new ArgumentNullException("Source FilePath.");
if (String.IsNullOrWhiteSpace(destFilePath))
destFilePath = Path.GetFileName(srcFilePath);
Uri serverUri = GetUri(srcFilePath);
//// the serverUri should start with the ftp:// scheme.
if (serverUri.Scheme != Uri.UriSchemeFtp)
return false;
FtpWebRequest request = CreateFtpRequest(serverUri, WebRequestMethods.Ftp.DownloadFile);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream fileStream = new FileStream(destFilePath, FileMode.OpenOrCreate, FileAccess.Write);
byte[] buffer = new byte[32 * 1024];
while(true) {
int bytesRead = responseStream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
break;
fileStream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
Console.WriteLine("Response status: {0} - {1}", response.StatusCode, response.StatusDescription);
return true;
}
/// <summary>
/// List an FTP folder's content
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string List(string path)
{
Uri serverUri = GetUri(path);
//// the serverUri should start with the ftp:// scheme.
if (serverUri.Scheme != Uri.UriSchemeFtp)
return "";
FtpWebRequest request = CreateFtpRequest(serverUri, WebRequestMethods.Ftp.ListDirectory);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
string result = sr.ReadToEnd();
Console.WriteLine("Response status: {0} - {1}", response.StatusCode, response.StatusDescription + "\r\n" + result);
return result;
}
private static FtpWebRequest CreateFtpRequest(Uri serverUri, string method)
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
request.EnableSsl = true;
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = true;
request.Credentials = new NetworkCredential(username, password);
request.Method = method;
return request;
}
private static Uri GetUri(string remoteFilePath)
{
Uri ftpServerUri = new Uri("ftp://" + ftpServer);
return new Uri(ftpServerUri, remoteFilePath);
}
}
}