1

我已经包装了大部分 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);

最终编辑

在 codeplex 上发布了这段代码

4

2 回答 2

4

你为什么要500 Syntax errors?

请记住,与 FTP 客户端(如ftp.exe)不同,实际的FTP 协议不接受类似的命令ls,它接受类似LISTNLST

有关 FTP接受的命令列表,请参阅原始 FTP 命令列表RFC 959

如何获得LISTorNLST命令的结果?

最后一个参数FtpCommand

指向在打开有效数据套接字时创建的句柄的指针。该 fExpectResponse参数必须设置为TRUE用于phFtpCommand填充。

您可以使用此句柄来读出列表InternetReadFile

笔记:

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

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

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

于 2009-03-24T22:27:14.480 回答