Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
766 views
in Technique[技术] by (71.8m points)

.net - FTP multiple files in C# without reestablishing connection

The FTP protocol is designed to support a control channel, and use that control channel to tell the server to open TCP connections and transfer files.

The server sending or receiving files does NOT have to be the same as the server that the FTP control channel is connected to. It can be a "triangle" type connection.

It also allows the client to log in once on the control channel, and repeatedly tell the server to transfer files, without re-logging into the control channel.

Apparently, this concept has completely escaped MS when they created the C# FtpWebRequest class.

I need to do exactly what the FTP protocol was designed to do:

  1. Connect to a server

  2. Pass in credentials

  3. Create directories (and happily ignore an 'already exists' error)

  4. Repeatedly transfer files up to the server

  5. Log out of the control channel

I sure am not seeing that ability in the FtpWebRequest class. Or anything that would appear to allow that kind of a flow in C# code.

I have looked:

But none of this seems to allow control that way it was meant to be.

I can specify the KeepAlive property, but the loop has to repeatedly call the WebRequest.Create(targetName); function, which would create a NEW connection, and get a NEW response. Then they fall out of scope or are orphaned, so by definition, they are destroyed. Therefore the connection MUST be closed, and then will have to be reopened. For a data connection, that's okay, but where is the ability to manipulate the CONTROL port?

The class doesn't allow the user to differentiate from a CONTROL port and a DATA port, as the FTP specification defines.

Is there a ways to use a C# class to do FTP the way it was meant to be? Because in Microsoft's narrow mindset, the whole world looks like an HTTP Get/Response protocol.

Any advice is appreciated.

-Scotty

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

FtpWebRequest works on top of a connection pool. So it actually implicitly reuses an underlying FTP connection, as long as the FtpWebRequest.KeepAlive is set to its default value of true.

When the KeepAlive is set to true, the underlying FTP (control) connection is not closed, when a request finishes. When you create another instance of the FtpWebRequest with the same host, port and username, the connection from previous request(s) is reused.


Take this simple example of two file upload requests to the same FTP server:

WebRequest request1 = WebRequest.Create("ftp://ftp.example.com/file1.zip");
request1.Credentials = new NetworkCredential("username", "password");
request1.Method = WebRequestMethods.Ftp.UploadFile;

using (Stream fileStream = File.OpenRead(@"C:pathfile1.zip"))
using (Stream ftpStream = request1.GetRequestStream())
{
    fileStream.CopyTo(ftpStream);
}

WebRequest request2 = WebRequest.Create("ftp://ftp.example.com/file2.zip");
request2.Credentials = new NetworkCredential("username", "password");
request2.Method = WebRequestMethods.Ftp.UploadFile;

using (Stream fileStream = File.OpenRead(@"C:pathfile2.zip"))
using (Stream ftpStream = request2.GetRequestStream())
{
    fileStream.CopyTo(ftpStream);
}

If you enable .NET network logging, you will see that only one FTP control connection is opened to the server:

FtpWebRequest#45004109::.ctor(ftp://ftp.example.com/file1.zip)
FtpWebRequest#45004109::GetRequestStream(Method=STOR.)
Current OS installation type is 'Client'.
RAS supported: True
FtpControlStream#21454193 - Created connection from 127.0.0.1:60360 to 93.184.216.34:2121.
Associating FtpWebRequest#45004109 with FtpControlStream#21454193
FtpControlStream#21454193 - Received response [220 ...]
FtpControlStream#21454193 - Sending command [USER username]
FtpControlStream#21454193 - Received response [331 Password required for username]
FtpControlStream#21454193 - Sending command [PASS ********]
FtpControlStream#21454193 - Received response [230 Logged on]
FtpControlStream#21454193 - Sending command [OPTS utf8 on]
FtpControlStream#21454193 - Received response [202 UTF8 mode is always enabled. No need to send this command.]
FtpControlStream#21454193 - Sending command [PWD]
FtpControlStream#21454193 - Received response [257 "/" is current directory.]
FtpControlStream#21454193 - Sending command [TYPE I]
FtpControlStream#21454193 - Received response [200 Type set to I]
FtpControlStream#21454193 - Sending command [PASV]
FtpControlStream#21454193 - Received response [227 Entering Passive Mode (93,184,216,34,247,106)]
FtpControlStream#21454193 - Sending command [STOR file1.zip]
FtpControlStream#21454193 - Received response [150 Opening data channel for file upload to server of "/file1.zip"]
FtpControlStream#21454193 - Received response [226 Successfully transferred "/file1.zip"]
FtpWebRequest#45004109::(Releasing FTP connection#21454193.)
FtpWebRequest#58870012::.ctor(ftp://ftp.example.com/file2.zip)
FtpWebRequest#58870012::GetRequestStream(Method=STOR.)
Associating FtpWebRequest#58870012 with FtpControlStream#21454193
FtpControlStream#21454193 - Sending command [PASV]
FtpControlStream#21454193 - Received response [227 Entering Passive Mode (93,184,216,34,247,142)]
FtpControlStream#21454193 - Sending command [STOR file2.zip]
FtpControlStream#21454193 - Received response [150 Opening data channel for file upload to server of "/file2.zip"]
FtpControlStream#21454193 - Received response [226 Successfully transferred "/file2.zip"]
FtpWebRequest#58870012::(Releasing FTP connection#21454193.)

Note that this does not work in .NET Core:
Download multiple files over FTP using one connection in .NET Core


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...