【问题标题】:How do I get the results from an FTP command run through FtpCommand?如何从通过 FtpCommand 运行的 FTP 命令获取结果?
【发布时间】:2011-11-04 22:02:41
【问题描述】:

我已经打包了大部分 wininet 没有问题,但现在我被卡住了。我正在尝试从 wininet.dll p/invoke 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

【问题讨论】:

  • @Daniel。是的,我也这么认为。我已经稍微更改了函数,以便根据命令,它可能会或可能不会期望数据套接字。我可以成功发送 PASV 命令,但是当我尝试从 FtpCommand 调用返回的 dataSocket 句柄中读取时,我得到了相同的结果。
  • 最坏的情况你可以使用 PORT 命令和 TcpListener 的组合;它看起来不那么漂亮,但它确实有效。

标签: c# winapi ftp pinvoke


【解决方案1】:

你为什么收到500 Syntax errors?

请记住,与 FTP 客户端(如 ftp.exe)不同,实际的 FTP protocol 不接受像 ls 这样的命令,它接受像 LISTNLST 这样的命令

请参阅Raw FTP Command ListRFC 959 获取 FTP 接受的命令列表

如何获得LISTNLST 命令的结果?

FtpCommand的最后一个参数是

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

您可以使用此句柄读取带有InternetReadFile 的列表。

注意事项:

  • 您可以考虑使用 WireShark 之类的东西来查看 ftp.exe 发送的实际网络流量,并将其与您的代码发送的流量进行比较
  • 您也可以考虑查看FtpWebRequest;如果它满足您的需求,它可能会更易于使用。

【讨论】:

  • FtpWebRequest 对我不起作用。在某些情况下我可以使用它,但我在使用它时遇到了其他问题。
  • 当我将在 dataSocket 中接收到的句柄传递给 InternetReadFile 时,应用程序会在调用后退出,没有错误或异常。如果我传递 HINTERNET 句柄,则调用有效,返回 false 并且 bytesRead 的数量 = 0
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2015-03-30
    • 2016-04-22
    • 1970-01-01
    相关资源
    最近更新 更多