Solved

FTP Sockets Async vs Sync?

Posted on 2012-12-30
12
1,172 Views
Last Modified: 2012-12-31
I currently have a nice FTP app using FtpWebResponse. Now I want to try C# Socket programming for a FTP client.

Q. Do you recommend Asynchronous or Synchronous sockets?

The synchronous Client code I've seen seems to appears to lockout any other FTP clients requests. Whereas asynchronous Client code seems more server friendly. Your thoughts please.

I don't think FtpWebResponse is either asynchronous or synchronous.
0
Comment
Question by:pointeman
  • 4
  • 4
  • 2
  • +2
12 Comments
 
LVL 18

Expert Comment

by:Gary Davis
ID: 38731021
For Windows 8 or Windows Phone 8 you can use the StreamSocket for async socket communications that you can use to implement your FTP. Something like this which also includes timeout checking.

using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

public class SocketService
{
    private static StreamSocket Socket { get; set; }

    /// <summary>
    /// Call like this: var socket = await ConnectToTivo();
    /// Socket can then be used for reaw/writes
    /// </summary>
    /// <returns>Connected Socket or null if timeout/error</returns>
    public static async Task<StreamSocket> ConnectSocket(string ip, string port)
    {
        if (Socket != null) return Socket; // Already connected

        Socket = new StreamSocket();

        var cancelToken = new CancellationTokenSource();
        cancelToken.CancelAfter(2000); // Two second timeout

        try
        {
            var op1 = Socket.ConnectAsync(new HostName(ip), port);
            var task = op1.AsTask(cancelToken.Token);
            await task;
        }
        catch (TaskCanceledException timeoutEx)
        {
            // TODO: Handle timeout
            return null;
        }
        catch (Exception ex)
        {
            // TODO: Handle exception
            return null;
        }

        // Do you expect any data after connect? If so, read it
        var reader = new DataReader(Socket.InputStream) {InputStreamOptions = InputStreamOptions.Partial};

        cancelToken = new CancellationTokenSource();
        cancelToken.CancelAfter(2000);

        try
        {
            var op2 = reader.LoadAsync(100);
            var task = op2.AsTask((cancelToken.Token));
            await task;
        }
        catch (TaskCanceledException timeoutEx)
        {
            // TODO: Handle timeout
            return null;
        }
        catch (Exception ex)
        {
            // TODO: Handle exception
            return null;
        }

        var data = reader.ReadString(reader.UnconsumedBufferLength);
        // Do something with data after connect
        return Socket;
    }
}

Open in new window


Once you have the Socket, you can then use similar code to read/write on that socket or close the socket (Socket.Dispose()).

Gary Davis
0
 
LVL 74

Accepted Solution

by:
käµfm³d   👽 earned 134 total points
ID: 38731114
If you're going to write your own code using raw sockets, then make sure you have a solid understanding of the FTP protocol.

Whereas asynchronous Client code seems more server friendly.
Why would the synchronicity of the client have any bearing on the server?

I don't think FtpWebResponse is either asynchronous or synchronous.
I'm not sure what you mean by that--a method, not a class, would be synchronous--but it would have to be one or the other (or possibly both), don't you think?
0
 
LVL 85

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 133 total points
ID: 38731155
I agree with kaufmed.  Having wrote an FTP client with the Winsock control in VB6 years ago, the FTP protocol is mostly a guideline.  It was designed with human interaction in mind, not automation. Responses vary from server to server so you have to write custom code to handle each specific case.  Your code may break if you use it with a server your code has never seen before at it returns something you weren't anticipating.  Good luck...
0
 
LVL 16

Assisted Solution

by:AlexPace
AlexPace earned 133 total points
ID: 38731358
[...] Now I want to try C# Socket programming for a FTP client. [...]

If you are just doing it for fun do HTTP instead.  If this is for work... it is a bad idea.  If the FtpWebResponse has some limitation then try using a different library.  Even if you have to pay $1000 for a 3rd party FTP stack you will save your boss a LOT of money over the cost of doing it yourself.  The FTP standard does not specify a directory listing format so if this is for a commercial product you'll need to write a few dozen parsing routines and be prepared for users to write in and tells you it doesnt work with Open VMS, DEC VMS, IBM AS400, IBM 4690, Verizon, US Bank, Oracle, Novell, Glub Tech, or whatever server they are using which has a different format than the standard Unix listing which is itself very different than what IIS returns.  Don't open that ugly can of worms if you can avoid it.
0
 

Author Comment

by:pointeman
ID: 38731464
After some research I'm finding that FtpWebResponce is a synchronous class, hence it doesn't have actual login method. Each upload, download, list member is quick and dirty then connection closed.. It will also freeze a desktop app if not running on a separate thread.
You are correct, the FTP server doesn't care if my code is synchronous or asynchronous. This a matter of block or not blocking threads.
I'm very familiar with the complexities of FTP commands worked with these servers many times. This is a personal project so I'm not concerned with the boss. I do understand your suggestion about plugins.
I've worked with TCP sockets and Server/Client programming before and find it very interesting. My original post is my concern on communicating with an FTP server, sync or async socket code.
Thank you for your input.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 38731595
So is your question more or less about keeping your application responsive? If so, is there any reason why you wouldn't keep the FTP stuff on another thread? Why do you think sockets would help you here?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:pointeman
ID: 38731751
I will have more creativity using Sockets when dealing with FTP commands wheras FtpWebRequest does not. In fact a newly created URI requires a login if not using anonymous. So changing a directory is a pain. Sockets will provide raw FTP command control. I digress.
Anyway, this post has given me some ideas.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 38731787
Ok...you can just use TcpClient to connect to the server then.  Everything is sent back and forth as ASCII.  Convert your string commands to a byte arrays using something like:

    byte[] cmd = System.Text.ASCIIEncoding.ASCII.GetBytes("FTP Command Here");

You can convert responses received as byte arrays back to a string using System.Text.ASCIIEncoding.ASCII.GetString().
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 38731864
Honestly, I am wondering if you have set up your code in the correct way. You shouldn't need to log in to the server again unless you have forcibly severed the connection (or it has been dropped for some uncontrollable reason). Take for example the following:

using System;
using System.IO;
using System.Net;

namespace _27980937
{
    class Program
    {
        static void Main(string[] args)
        {
            FtpWebRequest request = FtpWebRequest.Create("ftp://kenneth@localhost:21") as FtpWebRequest;
            FtpWebResponse response;

            request.Method = WebRequestMethods.Ftp.ListDirectory;

            response = request.GetResponse() as FtpWebResponse;
            Console.WriteLine(response.StatusDescription);

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                while (!reader.EndOfStream)
                {
                    Console.WriteLine(reader.ReadLine());
                }
            }

            request = FtpWebRequest.Create("ftp://kenneth@localhost:21/test") as FtpWebRequest;
            request.Method = WebRequestMethods.Ftp.MakeDirectory;
            response = request.GetResponse() as FtpWebResponse;
            Console.WriteLine(response.StatusDescription);

            request = FtpWebRequest.Create("ftp://kenneth@localhost:21/test") as FtpWebRequest;
            request.Method = WebRequestMethods.Ftp.ListDirectory;

            response = request.GetResponse() as FtpWebResponse;
            Console.WriteLine(response.StatusDescription);

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                while (!reader.EndOfStream)
                {
                    Console.WriteLine(reader.ReadLine());
                }
            }

            request = FtpWebRequest.Create("ftp://kenneth@localhost:21/test/example.txt") as FtpWebRequest;
            request.Method = WebRequestMethods.Ftp.UploadFile;

            using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
            {
                writer.WriteLine("hello world!");
            }

            response = request.GetResponse() as FtpWebResponse;

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                while (!reader.EndOfStream)
                {
                    Console.WriteLine(reader.ReadLine());
                }
            }

            request = FtpWebRequest.Create("ftp://kenneth@localhost:21/test") as FtpWebRequest;
            request.Method = WebRequestMethods.Ftp.ListDirectory;

            response = request.GetResponse() as FtpWebResponse;
            Console.WriteLine(response.StatusDescription);

            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                while (!reader.EndOfStream)
                {
                    Console.WriteLine(reader.ReadLine());
                }
            }
        }
    }
}

Open in new window


And the conversation:

FTP Server Log
As you can see, only one USER and PASS commands have been sent for the whole session.

You might also look into the ConnectionGroupName and KeepAlive properties to help ensure only one connection is used.
0
 

Author Comment

by:pointeman
ID: 38732433
The original post is "FTP Sockets Async vs Sync?". I'm satisfied with the Socket question.

I think we need to pickup this prior EE question concerning FtpWebRequest. Thank you Kaufmed for all your help. http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_27974557.html
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 38732686
The impression I got was that you wanted to use sockets because you felt you were limited in the functionality of FtpWebRequest/FtpWebResponse. If it is more of a learning issue, then by all means proceed with the socket approach (I've done so myself in the past). If this is because you want a custom FTP client, then I think the work involved is going to be much greater when dealing with raw sockets than with the existing FTP classes.

In either case, good luck, and I (and others, I'm sure) are happy to help where I can  : )
0
 

Author Closing Comment

by:pointeman
ID: 38732880
This was difficult to grade, thx
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now