i wrote my custom ftp client class and try to download a file from my ftp server.
also i tried httpwebrequest and download a file from http server..
but the speed is about 16kbit per second, is this the speed limit? or am i making mistake?
here is my ftp class
using System; using System.IO; using Microsoft.SPOT; using System.Text; using System.Threading; using System.Net.Sockets; using System.Net; namespace smg.ftp { public class FtpClient { public class FtpException : Exception { public FtpException(string message) : base(message) { } public FtpException(string message, Exception innerException) : base(message, innerException) { } } private static int BUFFER_SIZE = 2048; private static Encoding ASCII = Encoding.UTF8; private bool verboseDebugging = false; // defaults private string server = "localhost"; private string remotePath = "."; private string username = "anonymous"; private string password = "anonymous@anonymous.net"; private string message = null; private string result = null; private int port = 21; private int bytes = 0; private int resultCode = 0; private bool loggedin = false; private bool binMode = false; private Byte[] buffer = new Byte[BUFFER_SIZE]; private Socket clientSocket = null; private int timeoutSeconds = 300; /// <summary> /// Default contructor /// </summary> public FtpClient() { } /// <summary> /// /// </summary> /// <param name="server"></param> /// <param name="username"></param> /// <param name="password"></param> public FtpClient(string server, string username, string password) { this.server = server; this.username = username; this.password = password; } /// <summary> /// /// </summary> /// <param name="server"></param> /// <param name="username"></param> /// <param name="password"></param> /// <param name="timeoutSeconds"></param> /// <param name="port"></param> public FtpClient(string server, string username, string password, int timeoutSeconds, int port) { this.server = server; this.username = username; this.password = password; this.timeoutSeconds = timeoutSeconds; this.port = port; } /// <summary> /// Display all communications to the debug log /// </summary> public bool VerboseDebugging { get { return this.verboseDebugging; } set { this.verboseDebugging = value; } } /// <summary> /// Remote server port. Typically TCP 21 /// </summary> public int Port { get { return this.port; } set { this.port = value; } } /// <summary> /// Timeout waiting for a response from server, in seconds. /// </summary> public int Timeout { get { return this.timeoutSeconds; } set { this.timeoutSeconds = value; } } /// <summary> /// Gets and Sets the name of the FTP server. /// </summary> /// <returns></returns> public string Server { get { return this.server; } set { this.server = value; } } /// <summary> /// Gets and Sets the port number. /// </summary> /// <returns></returns> public int RemotePort { get { return this.port; } set { this.port = value; } } /// <summary> /// GetS and Sets the remote directory. /// </summary> public string RemotePath { get { return this.remotePath; } set { this.remotePath = value; } } /// <summary> /// Gets and Sets the username. /// </summary> public string Username { get { return this.username; } set { this.username = value; } } /// <summary> /// Gets and Set the password. /// </summary> public string Password { get { return this.password; } set { this.password = value; } } /// <summary> /// If the value of mode is true, set binary mode for downloads, else, Ascii mode. /// </summary> public bool BinaryMode { get { return this.binMode; } set { if (this.binMode == value) return; if (value) sendCommand("TYPE I"); else sendCommand("TYPE A"); if (this.resultCode != 200) throw new FtpException(result.Substring(4)); } } /// <summary> /// Login to the remote server. /// </summary> public void Login() { if (this.loggedin) this.Close(); Debug.Print("Opening connection to " + this.server + "FtpClient"); IPEndPoint ep = null; try { this.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ep = new IPEndPoint(IPAddress.Parse(this.server), this.port); this.clientSocket.Connect(ep); } catch (Exception ex) { // doubtfull if (this.clientSocket != null) this.clientSocket.Close(); throw new FtpException("Couldn't connect to remote server", ex); } this.readResponse(); if (this.resultCode != 220) { this.Close(); throw new FtpException(this.result.Substring(4)); } this.sendCommand("USER " + username); if (!(this.resultCode == 331 || this.resultCode == 230)) { this.cleanup(); throw new FtpException(this.result.Substring(4)); } if (this.resultCode != 230) { this.sendCommand("PASS " + password); if (!(this.resultCode == 230 || this.resultCode == 202)) { this.cleanup(); throw new FtpException(this.result.Substring(4)); } } this.loggedin = true; Debug.Print("Connected to " + this.server + "FtpClient"); } /// <summary> /// Close the FTP connection. /// </summary> public void Close() { Debug.Print("Closing connection to " + this.server + "FtpClient"); if (this.clientSocket != null) { this.sendCommand("QUIT"); } this.cleanup(); } /// <summary> /// Return the size of a file. /// </summary> /// <param name="fileName"></param> /// <returns></returns> public long GetFileSize(string fileName) { if (!this.loggedin) this.Login(); this.sendCommand("SIZE " + fileName); long size = 0; if (this.resultCode == 213) size = long.Parse(this.result.Substring(4)); else throw new FtpException(this.result.Substring(4)); return size; } /// <summary> /// Download a file to the Assembly's local directory, /// keeping the same file name. /// </summary> /// <param name="remFileName"></param> public void Download(string remFileName) { this.Download(remFileName, "", false); } /// <summary> /// Download a remote file to the Assembly's local directory, /// keeping the same file name, and set the resume flag. /// </summary> /// <param name="remFileName"></param> /// <param name="resume"></param> public void Download(string remFileName, Boolean resume) { this.Download(remFileName, "", resume); } /// <summary> /// Download a remote file to a local file name which can include /// a path. The local file name will be created or overwritten, /// but the path must exist. /// </summary> /// <param name="remFileName"></param> /// <param name="locFileName"></param> public void Download(string remFileName, string locFileName) { this.Download(remFileName, locFileName, false); } /// <summary> /// Download a remote file to a local file name which can include /// a path, and set the resume flag. The local file name will be /// created or overwritten, but the path must exist. /// </summary> /// <param name="remFileName"></param> /// <param name="locFileName"></param> /// <param name="resume"></param> public void Download(string remFileName, string locFileName, Boolean resume) { if (!this.loggedin) this.Login(); // this.BinaryMode = true; Debug.Print("Downloading file " + remFileName + " from " + server + "/" + remotePath + "FtpClient"); if (locFileName.Equals("")) { locFileName = remFileName; } FileStream output = null; if (!File.Exists(locFileName)) output = File.Create(locFileName); else output = new FileStream(locFileName, FileMode.Open); Socket cSocket = createDataSocket(); long offset = 0; if (resume) { offset = output.Length; if (offset > 0) { this.sendCommand("REST " + offset); if (this.resultCode != 350) { //Server dosnt support resuming offset = 0; Debug.Print("Resuming not supported:" + result.Substring(4) + "FtpClient"); } else { Debug.Print("Resuming at offset " + offset + "FtpClient"); output.Seek(offset, SeekOrigin.Begin); } } } this.sendCommand("RETR " + remFileName); if (this.resultCode != 150 && this.resultCode != 125) { throw new FtpException(this.result.Substring(4)); } DateTime timeout = DateTime.Now.AddSeconds(this.timeoutSeconds); while (timeout > DateTime.Now) { this.bytes = cSocket.Receive(buffer, buffer.Length, 0); //output.Write(this.buffer, 0, this.bytes); //Thread.Sleep(1); if (this.bytes <= 0) { break; } } output.Close(); try { cSocket.Close(); } catch (Exception) { } this.readResponse(); if (this.resultCode != 226 && this.resultCode != 250) throw new FtpException(this.result.Substring(4)); } /// <summary> /// /// </summary> private void readResponse() { this.message = ""; this.result = this.readLine(); if (this.result.Length > 3) this.resultCode = int.Parse(this.result.Substring(0, 3)); else this.result = null; } /// <summary> /// /// </summary> /// <returns></returns> private string readLine() { while (true) { this.bytes = clientSocket.Receive(this.buffer, this.buffer.Length, 0); char[] cc = ASCII.GetChars(this.buffer); this.message += new string(cc).Substring(0, this.bytes); //this.message += ASCII.GetString(this.buffer, 0, this.bytes); Thread.Sleep(10); if (this.bytes < this.buffer.Length) { break; } } Thread.Sleep(100); string[] msg = this.message.Split('\n'); if (this.message.Length > 2) { if (msg.Length>=2) { this.message = msg[msg.Length - 2]; } else { this.message = msg[0]; } } else { this.message = msg[0]; } if (this.message.Length > 4 && !this.message.Substring(3, 1).Equals(" ")) return this.readLine(); if (this.verboseDebugging) { for (int i = 0; i < msg.Length - 1; i++) { Debug.Print(msg[i] + "FtpClient"); } } return message; } /// <summary> /// /// </summary> /// <param name="command"></param> private void sendCommand(String command) { if (this.verboseDebugging) Debug.Print(command + "FtpClient"); //Byte[] cmdBytes = Encoding.UTF8.GetBytes(command + "\r\n"); Byte[] cmdBytes = ASCII.GetBytes(command + "\r\n"); clientSocket.Send(cmdBytes, cmdBytes.Length, 0); this.readResponse(); } /// <summary> /// when doing data transfers, we need to open another socket for it. /// </summary> /// <returns>Connected socket</returns> private Socket createDataSocket() { this.sendCommand("PASV"); if (this.resultCode != 227) throw new FtpException(this.result.Substring(4)); int index1 = this.result.IndexOf('('); int index2 = this.result.IndexOf(')'); string ipData = this.result.Substring(index1 + 1, index2 - index1 - 1); int[] parts = new int[6]; string[] sparts = ipData.Split(','); for (int i = 0; i < parts.Length; i++) { parts[i] = int.Parse(sparts[i]); } int len = ipData.Length; int partCount = 0; string buf = ""; //for (int i = 0; i < len && partCount <= 6; i++) //{ // char[] charr = ipData.Substring(i, 1).ToCharArray(); // char ch = charr[0]; // if (int.Parse(ch.ToString()) >= 0) // buf += ch; // else if (ch != ',') // throw new FtpException("Malformed PASV result: " + result); // if (ch == ',' || i + 1 == len) // { // try // { // parts[partCount++] = int.Parse(buf); // buf = ""; // } // catch (Exception ex) // { // throw new FtpException("Malformed PASV result (not supported?): " + this.result, ex); // } // } //} string ipAddress = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3]; int port = (parts[4] << 8) + parts[5]; Socket socket = null; IPEndPoint ep = null; try { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ep = new IPEndPoint(IPAddress.Parse(ipAddress), port); socket.Connect(ep); } catch (Exception ex) { // doubtfull.... if (socket != null) socket.Close(); throw new FtpException("Can't connect to remote server", ex); } return socket; } /// <summary> /// Always release those sockets. /// </summary> private void cleanup() { if (this.clientSocket != null) { this.clientSocket.Close(); this.clientSocket = null; } this.loggedin = false; } /// <summary> /// Destuctor /// </summary> ~FtpClient() { this.cleanup(); } /**************************************************************************************************************/ #region Async methods (auto generated) /* WinInetApi.FtpClient ftp = new WinInetApi.FtpClient(); MethodInfo[] methods = ftp.GetType().GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Public); foreach ( MethodInfo method in methods ) { string param = ""; string values = ""; foreach ( ParameterInfo i in method.GetParameters() ) { param += i.ParameterType.Name + " " + i.Name + ","; values += i.Name + ","; } Debug.Print("private delegate " + method.ReturnType.Name + " " + method.Name + "Callback(" + param.TrimEnd(',') + ");"); Debug.Print("public System.IAsyncResult Begin" + method.Name + "( " + param + " System.AsyncCallback callback )"); Debug.Print("{"); Debug.Print("" + method.Name + "Callback ftpCallback = new " + method.Name + "Callback(" + values + " this." + method.Name + ");"); Debug.Print("return ftpCallback.BeginInvoke(callback, null);"); Debug.Print("}"); Debug.Print("public void End" + method.Name + "(System.IAsyncResult asyncResult)"); Debug.Print("{"); Debug.Print(method.Name + "Callback fc = (" + method.Name + "Callback) ((AsyncResult)asyncResult).AsyncDelegate;"); Debug.Print("fc.EndInvoke(asyncResult);"); Debug.Print("}"); //Debug.Print(method); } */ private delegate void LoginCallback(); public System.IAsyncResult BeginLogin(System.AsyncCallback callback) { LoginCallback ftpCallback = new LoginCallback(this.Login); return ftpCallback.BeginInvoke(callback, null); } private delegate void CloseCallback(); public System.IAsyncResult BeginClose(System.AsyncCallback callback) { CloseCallback ftpCallback = new CloseCallback(this.Close); return ftpCallback.BeginInvoke(callback, null); } private delegate Int64 GetFileSizeCallback(String fileName); public System.IAsyncResult BeginGetFileSize(String fileName, System.AsyncCallback callback) { GetFileSizeCallback ftpCallback = new GetFileSizeCallback(this.GetFileSize); return ftpCallback.BeginInvoke(fileName, callback, null); } private delegate void DownloadCallback(String remFileName); public System.IAsyncResult BeginDownload(String remFileName, System.AsyncCallback callback) { DownloadCallback ftpCallback = new DownloadCallback(this.Download); return ftpCallback.BeginInvoke(remFileName, callback, null); } private delegate void DownloadFileNameResumeCallback(String remFileName, Boolean resume); public System.IAsyncResult BeginDownload(String remFileName, Boolean resume, System.AsyncCallback callback) { DownloadFileNameResumeCallback ftpCallback = new DownloadFileNameResumeCallback(this.Download); return ftpCallback.BeginInvoke(remFileName, resume, callback, null); } private delegate void DownloadFileNameFileNameCallback(String remFileName, String locFileName); public System.IAsyncResult BeginDownload(String remFileName, String locFileName, System.AsyncCallback callback) { DownloadFileNameFileNameCallback ftpCallback = new DownloadFileNameFileNameCallback(this.Download); return ftpCallback.BeginInvoke(remFileName, locFileName, callback, null); } private delegate void DownloadFileNameFileNameResumeCallback(String remFileName, String locFileName, Boolean resume); public System.IAsyncResult BeginDownload(String remFileName, String locFileName, Boolean resume, System.AsyncCallback callback) { DownloadFileNameFileNameResumeCallback ftpCallback = new DownloadFileNameFileNameResumeCallback(this.Download); return ftpCallback.BeginInvoke(remFileName, locFileName, resume, callback, null); } #endregion } }
here how i use it
FtpClient ftp = new FtpClient("192.168.1.21", "mtest", "mtest", 1000, 21); ftp.Download("test.MP3", "\\SD\\bb.mp3", true);
before i start ftp download
here is my dhcp configuration
static private void InitNetwork() { // write your code here NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface networkInterface in networkInterfaces) { if (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet) { if (!networkInterface.IsDhcpEnabled) { // Switch to DHCP ... networkInterface.EnableDhcp(); networkInterface.RenewDhcpLease(); Thread.Sleep(10000); } Debug.Print("IP Address: " + networkInterface.IPAddress); Debug.Print("Subnet mask " + networkInterface.SubnetMask); Debug.Print("Gateway " + networkInterface.GatewayAddress); Debug.Print("DNS " + networkInterface.DnsAddresses[0]); } } }
also as i told, i write an http downloader, speed is the same with it..
here is the http downloader
using System; using Microsoft.SPOT; using System.IO; using System.Net; using System.Net.Sockets; namespace smg.utulity.downloader { class downloader { public static event Progress onProgress; public delegate void Progress(long currentSize, long TotalSize, string Filename); public static event DownloadFinished onDownloadFinished; public delegate void DownloadFinished(string errMsg); public static int DownloadFile(String remoteFilename, String localFilename) { string fname = localFilename.Split('\\')[localFilename.Split('\\').Length - 1]; // Function will return the number of bytes processed // to the caller. Initialize to 0 here. int bytesProcessed = 0; // Assign values to these objects here so that they can // be referenced in the finally block Stream remoteStream = null; Stream localStream = null; WebResponse response = null; // Use a try/catch/finally block as both the WebRequest and Stream // classes throw exceptions upon error try { // Create a request for the specified remote file name WebRequest request = WebRequest.Create(remoteFilename); if (request != null) { // Send the request to the server and retrieve the // WebResponse object // request.ContentLength response = request.GetResponse(); if (response != null) { // Once the WebResponse object has been retrieved, // get the stream object associated with the response's data remoteStream = response.GetResponseStream(); long total = response.ContentLength; // Create the local file localStream = File.Create(localFilename); // Allocate a 1k buffer byte[] buffer = new byte[1024]; int bytesRead; // Simple do/while loop to read from stream until // no bytes are returned do { // Read data (up to 1k) from the stream bytesRead = remoteStream.Read(buffer, 0, buffer.Length); // Write the data to the local file localStream.Write(buffer, 0, bytesRead); // Increment total bytes processed bytesProcessed += bytesRead; if (onProgress != null) { onProgress(bytesProcessed, total, fname); } } while (bytesRead > 0); } } if (onDownloadFinished != null) { onDownloadFinished("finished"); } } catch (WebException webEx) { Debug.Print("Web Exception Occured"); if (webEx.InnerException is SocketException) { SocketException sock = webEx.InnerException as SocketException; Debug.Print("Socket error code: " + sock.ErrorCode.ToString()); } } catch (Exception ex) { Debug.Print("Exception of type: " + ex.GetType().FullName); Debug.Print(ex.Message); if (onDownloadFinished != null) { onDownloadFinished(ex.Message); } } finally { // Close the response and streams objects here // to make sure they're closed even if an exception // is thrown at some point if (response != null) response.Close(); if (remoteStream != null) remoteStream.Close(); if (localStream != null) localStream.Close(); } // Return total bytes processed to caller. return bytesProcessed; } } }
here is how i used it
public static void Main() { downloader.onProgress += new downloader.Progress(downloader_onProgress); downloader.onDownloadFinished += new downloader.DownloadFinished(downloader_onDownloadFinished); int filesize = downloader.DownloadFile("http://192.168.1.21/test.MP3", "\\SD\\deneme1.mp3"); } static void downloader_onDownloadFinished(string errMsg) { Debug.Print("download finished" + errMsg); } static void downloader_onProgress(long currentSize, long TotalSize, string Filename) { Debug.Print("c:" + currentSize + "-t:" + TotalSize + "-f:" + Filename); }
my network connection is 100mbit..
my internet speed is 10 mbit.. my pc downloads the same file with 800-900kbit/s
but netduino plus downloads at 16-20kbit/s
how can i improve speed?
note: i am using MF 4.2 and when using system.ftp (also adding system.http) , i cant deploy the application..
can anyone show me a better way?