System.Net.FtpClient库

时间:2016-02-26 16:33:49

标签: c# ftp

我使用此库连接到远程FTP服务器并下载库存(csv)文件:https://netftp.codeplex.com/

我已经完成了连接,下载和安装;包装器中的断开序列如下:

class FTPConnection
{
    /// <summary>
    /// Private class objects.
    /// </summary>
    private string ftpHost;
    private string ftpUser;
    private string ftpPass;
    private string ftpDocRoot;
    private int ftpPort;
    private int ftpTimeout;
    private FtpClient ftpClient;

    /// <summary>
    /// Class constructor.
    /// </summary>
    /// <param name="ftpHost"></param>
    /// <param name="ftpPort"></param>
    /// <param name="ftpUser"></param>
    /// <param name="ftpPass"></param>
    /// <param name="ftpDocRoot"></param>
    /// <param name="ftpTimeout"></pparam>
    public FTPConnection(string ftpHost, int ftpPort, string ftpUser, string ftpPass, string ftpDocRoot, int ftpTimeout = 30)
    {
        // Remember settings
        this.ftpHost = ftpHost;
        this.ftpPort = ftpPort;
        this.ftpUser = ftpUser;
        this.ftpPass = ftpPass;
        this.ftpDocRoot = ftpDocRoot;
        this.ftpTimeout = ftpTimeout;
    }

    /// <summary>
    /// Method to test connection.
    /// </summary>
    /// <returns></returns>
    public bool Test()
    {
        // Connect to ftp server
        Connect();

        // Check if connected
        bool isConnected = ftpClient.IsConnected;

        // Disconnect
        Disconnect();

        // Finished
        return isConnected;
    }

    /// <summary>
    /// Method to download stock file from ftp server.
    /// </summary>
    /// <param name="stockFileDir"></param>
    /// <param name="supplierId"></param>
    /// <param name="stockFileNamePattern"></param>
    /// <returns></returns>
    public string DownloadStockFile(string stockFileDir, int supplierId, string stockFileNamePattern)
    {
        // Init
        string localFilePath = "";

        // Connect to ftp server
        Connect();

        // Load remote ftp server files
        foreach (FtpListItem ftpListItem in ftpClient.GetListing(stockFileDir, FtpListOption.Modify | FtpListOption.Size))
        {
            if (ftpListItem.Type == FtpFileSystemObjectType.File && ftpListItem.Name.Contains(stockFileNamePattern))
            {
                localFilePath = string.Format(@"{0}\{1}_{2}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), supplierId, ftpListItem.Name);
                if (File.Exists(localFilePath)) File.Delete(localFilePath);
                using (var ftpStream = ftpClient.OpenRead(ftpListItem.FullName))
                using (var fileStream = File.Create(localFilePath, (int)ftpStream.Length))
                {
                    var buffer = new byte[8 * 1024];
                    int count;
                    while ((count = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fileStream.Write(buffer, 0, count);
                    }
                    break;
                }
            }
        }

        // Disconnect
        Disconnect();

        // Finished
        return localFilePath;
    }

    /// <summary>
    /// Method to connect to ftp server.
    /// </summary>
    private void Connect()
    {
        // Connect to ftp server
        if (null == ftpClient || !ftpClient.IsConnected)
        {
            ftpClient = new FtpClient();
            ftpClient.Encoding = Encoding.UTF8;
            ftpClient.Host = ftpHost;
            ftpClient.Port = ftpPort;
            ftpClient.ConnectTimeout = 1000 * ftpTimeout;
            ftpClient.Credentials = new NetworkCredential(ftpUser, ftpPass);
            ftpClient.Connect();
            ftpClient.SetWorkingDirectory(ftpDocRoot);
        }
    }

    /// <summary>
    /// Method to disconnect from ftp server.
    /// </summary>
    private void Disconnect()
    {
        try
        {
            ftpClient.Disconnect();
        }
        catch { }
        finally
        {
            if (null != ftpClient)
                ftpClient.Dispose();
            ftpClient = null;
        }
    }
}

这用于“同步”应用程序,该应用程序轮询ftp服务器并按文件名模式抓取第一个匹配的文件。

这就是我使用包装器的方式:

// Init
string stockFilePath = string.Empty;

// Connect to ftp server and download the stock file
FTPConnection ftpConnection = null;
try
{
    // Init connection
    ftpConnection = new FTPConnection
    (
        supplierConfig.FTPHost,
        supplierConfig.FTPPort,
        supplierConfig.FTPUser,
        supplierConfig.FTPPass,
        supplierConfig.FTPDir
    );

    // Download stock file
    stockFilePath = ftpConnection.DownloadStockFile(supplierConfig.FTPDir, supplierConfig.PLSupplierAccountID, supplierConfig.StockFileNamePattern);
}
catch (Exception ex)
{
    // Re throw exception
    throw new Exception("Failed to download stock file - " + ex.Message);
}
finally
{
    // Clean-up
    ftpConnection = null;
}

代码执行时,它完全按预期工作。抓取文件并存储它并返回本地文件的完整路径。

然而,当代码再次执行时(在设定的间隔之后),我不断收到此错误:

  

已达到您帐户的最大连接数(4)。

但是,您可以在我的包装器中看到我正在关闭ftp连接并处理ftp客户端对象并进行清理。

知道我如何达到4的ftp帐户的最大连接数?

如果我要关闭应用并打开它,它会再次开始正常工作。这是远程ftp服务器的问题吗?它看起来只能连接一次。

3 个答案:

答案 0 :(得分:0)

您可以尝试将客户端包装在using块中,以查看是否可以重复连接整个对象:

using (FtpClient conn = new FtpClient()) {
     FtpReply reply;

     conn.Host = "localhost";
     conn.Credentials = new NetworkCredential("ftptest", "ftptest");

     if (!(reply = conn.Execute("SITE CHMOD 640 FOO.TXT")).Success) {
         throw new FtpCommandException(reply);
     }
}

答案 1 :(得分:0)

ftpConnection = null;没有关闭你的conn,你必须致电ftpConnection.Disconnect()

答案 2 :(得分:0)

我已经通过浏览System.Data.FtpClient上的可用选项来解决问题,看看它是否有KeepAlive / MaxConnection等的任何方法/设置....我遇到了这个选项:

EnableThreadSafeDataConnections

以下是此选项的作用:

  

当此值设置为true(默认值)时,将克隆控件连接   以及为数据通道操作建立服务器的新连接。   这是一种在单个上进行异步操作的线程安全方法   控制连接对开发人员来说是透明的。

所以,我已将此设置为false(因为我没有使用async方法),如下所示:

  

conn.EnableThreadSafeDataConnections = false;

我的问题解决了。基本上发生了什么,这个库保持连接打开,每次我断开(最多4个)像某种连接池。将此设置为false会阻止它执行此操作。

这是我的代码的最终工作版本:

/// <summary>
/// Method to download stock file from ftp server.
/// </summary>
/// <param name="stockFileDir"></param>
/// <param name="supplierId"></param>
/// <param name="stockFileNamePattern"></param>
/// <returns></returns>
public string DownloadStockFile(string stockFileDir, int supplierId, string stockFileNamePattern)
{
    // Init
    string localFilePath = "";

    // Load remote ftp server file
    using (FtpClient conn = new FtpClient())
    {
        // Set connection details
        conn.Encoding = Encoding.UTF8;
        conn.Host = ftpHost;
        conn.Port = ftpPort;
        conn.ConnectTimeout = 1000 * ftpTimeout;
        conn.Credentials = new NetworkCredential(ftpUser, ftpPass);
        conn.EnableThreadSafeDataConnections = false;

        // Get file listng
        foreach (FtpListItem ftpListItem in conn.GetListing(stockFileDir, FtpListOption.Modify | FtpListOption.Size))
        {
            // Proceed if this is a file
            if (ftpListItem.Type == FtpFileSystemObjectType.File && ftpListItem.Name.Contains(stockFileNamePattern))
            {
                // Download file
                localFilePath = string.Format(@"{0}\{1}_{2}", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), supplierId, ftpListItem.Name);
                if (File.Exists(localFilePath)) File.Delete(localFilePath);
                using (var ftpStream = conn.OpenRead(ftpListItem.FullName))
                using (var fileStream = File.Create(localFilePath, (int)ftpStream.Length))
                {
                    var buffer = new byte[8 * 1024];
                    int count;
                    while ((count = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fileStream.Write(buffer, 0, count);
                    }

                    // Stop further processing
                    break;
                }
            }
        }

        // Disconnect
        conn.Disconnect();
    }

    // Finished
    return localFilePath;
}

希望这有助于某人。