如何通过FtpCommand运行FTP命令获得结果?

时间:2009-03-24 15:33:47

标签: c# winapi ftp pinvoke

我把大部分的wininet包裹起来没有问题,但现在我被卡住了。我试图从wininet.dll调用FtpCommand,但我运行的每个命令都返回“500语法错误”。甚至像dir或ls这样的简单命令。如果我使用ftp.exe连接到同一服务器,则命令可以正常工作并返回预期结果。

以下是方法定义:

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError=true)]
extern public static int FtpCommand(
    [In]  IntPtr hConnect,      
    [In]  bool fExpectResponse, 
    [In]  int dwFlags,          
    [In]  string command,
    [In]  IntPtr dwContext,
    [In][Out]  ref int ftpCommand);

我在调用它的代码:

    public string SendCommand(string cmd)
    {
        int result;
        IntPtr dataSocket = new IntPtr();
        switch(cmd)
        {
            case "PASV":
                result = WININET.FtpCommand(_hConnect, false, WININET.FTP_TRANSFER_TYPE_ASCII, cmd, IntPtr.Zero, ref dataSocket);
                break;
            default:
                result = WININET.FtpCommand(_hConnect, true, WININET.FTP_TRANSFER_TYPE_ASCII, cmd, IntPtr.Zero, ref dataSocket);
                break;
        }

        Console.WriteLine(InternetLastResponseInfo());

        int BUFFER_SIZE = 8192;

        if(result == 0){
            Error();
        }
        else if(dataSocket != IntPtr.Zero)
        {
            StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
            int bytesRead = 0;

            do
            {
                result = WININET.InternetReadFile(dataSocket, buffer, BUFFER_SIZE, ref bytesRead);
            } while (result == 1 && bytesRead > 1);

            return buffer.ToString();

        }

        return "";
    }

其他一切正常,我可以使用FtpFindFirstFile()下载文件,上传文件和模仿dir命令,但我似乎无法使用上述方法发送命令。

修改

我的SendCommand代码刚刚是SendCommand(“DIR”)或SendCommand(“LS”)。在阅读其中一个答案(在我编辑时看不到谁)后,我将其更改为SendCommand(“LIST”)并成功返回。

但是,我的问题是如何读取结果,我用什么来读取LIST命令返回的数据,以便我可以以可读的格式输出?

我已经更新了SendCommand方法,以显示我计划如何读取返回的数据,但是对于bytesRead我总是得到0。我也尝试在FtpCommand调用中传递dataSocket接收到的句柄,但是如果我这样做,应用程序就会退出而没有错误。

编辑2

我正在使用InternetReadFile从我调用FtpCommand时返回的数据套接字的句柄中读取数据。我正在使用的InternetReadFile的方法签名是:

[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)]
extern public static int InternetReadFile(
    [In] IntPtr hConnect,
    [In][Out] StringBuilder buffer,
    [In] int buffCount,
    [In][Out] ref int bytesRead);

最终编辑

我发布了这个code on codeplex

2 个答案:

答案 0 :(得分:4)

您为什么会收到500 Syntax error

请注意,与FTP客户端(例如ftp.exe)不同,实际FTP protocol不会使用ls之类的命令,它会执行LIST和{{1}等命令}

有关FTP接受的命令列表,请参阅Raw FTP Command ListRFC 959

如何获得NLSTLIST命令的结果?

FtpCommand的最后一个参数是

  

指向创建的句柄的指针   如果打开了有效的数据套接字。该   必须设置NLST参数   fExpectResponse填写TRUE

您可以使用此句柄通过InternetReadFile读出列表。

备注:

  • 您可以考虑使用WireShark之类的内容查看phFtpCommand发送的实际网络流量,并将其与您的代码发送的内容进行比较
  • 你也可以考虑调查FtpWebRequest;如果它满足您的需求,它可能更容易使用。

答案 1 :(得分:1)

纠正我的问题的关键是确保发送原始FTP命令,而不是诸如“DIR”之类的命令,传递true(我期望数据套接字),并且方法声明中的CharSet是CharSet。 ANSI。如果我用CharSet.Auto或CharSet.Unicode替换CharSet.Ansi,我只会得到一堆乱码。

我已更新问题中的代码示例,以反映有效的方法。