[原译]C#编写FTP客户端软件

1 介绍

我知道。网上有很多现成的FTP软件。但是。我们也想要了解FTP的一些底层机构,因此。 这个开源的项目在你学习FTP知识的时候也许对你有些帮组。程序的界面看起来像FileZilla,FileZilla虽然流行但是有些bug,当我打开我博客的时候总是有问题。我需要通过FTP连接我的服务器。发送文件,下载文件等等。因为。我决定写我自己的软件来处理所有的情况。FileZilla足够好。但它不是我的。

 

2 背景

 

看看我们已经知道的。我们知道FTP是一个标准的基于TCP网络协议。用于从一个主机向另一个主机传输文件。它是一个C/S架构。

 

图2

 

FTP程序曾经是基于命令行的。我们仍沿可以通过cmd.exe连接FTP服务器。因为FTP的确可以通过命令来操作。举个例子。我们可以在命令行使用“stor”命令来发送文件。为了完成这些请求。FTP服务器需要一直运行等待即将到来的客户端请求。我们可以从来自维基百科的解释更好的理解FTP:

 

客户端计算机可以通过服务器的21端口和服务器通信。叫做控制连接。它在一次会话期间保持开放。第一次连接的时候。叫做数据连接,服务器可以对客户端打开20端口(主动模式),建立一条数据通路,连接上客户端传输数据。或者客户端打开一个随机的端口(被动模式),去连接服务器,来传输数据。控制连接使用一个类似Telnet的协议,被用作客户端和服务器会话管理(命令,标识,密码)。。比如。"RETR filename"  会从服务器端下载文件。

图三

一个完整的FTP文件传输需要建立两种类型的连接,一种为文件传输下命令,称为控制连接,另一种实现真正的文件传输,称为数据连接。

服务器 通过三位ASCII的数字状态码,可能包含可选的描述信息,在控制连接上做出回应。比如。“200”或者是“200 OK”,表示上一条命令成功了。数字代表编号,描述信息给出了一些说明(比如“OK”),或者可能是一些需要的参数(比如需要帐号来存储文件),那么我们需要怎么做呢。很明显。发送命令,接收“OK”回应,发送数据。接收数据。完了。但是首先需要服务器已经准备好了。FTP服务器可以在主动和被动两种模式下运行。主动模式是基于服务器的连接而被动模式是基友客户端的连接。继续看。

在主动连接中,客户端把自己的ip和端口发送给服务器。然后服务器尝试连接到客户端,但是可能会因为防火墙的原因而被拒绝。我们在windows上都会使用反病毒/自带防火墙。是吧。那么我们来看看被动模式

在被动连接中。服务器通过一个“PASV”命令把自己的ip和端口发送给客户端。然后客户端通过该IP尝试连接服务器。对于发送文件非常有用。当我们发送文件的时候。优先使用“PASV”模式,如你们所说。大多数协议。像FTP/HTTP 使用ASCII编码,因为全球可用。因此我们会使用这种编码。你可以从下面得到FTP的命令列表

主动和被动都是对于服务器端来说的

3 使用代码

现在我们已经为编写软件做好准备了。我们写些有用的代码吧。:)首先。我们“打开文件对话框”,集成到我们的窗体里。

3.1 资源管理器组件

我们需要一个资源管理器组件在软件界面可以看到我们所有的文件。这样我们才可以选择哪些文件来发送到FTP服务器,新建一个Windows窗体控件库(下载包中提供了)

图四

最后看起来样子是上面这样。先添加一个TreeView,一些按钮,和一个搜索功能

TreeView.Nodes.Clear();

TreeNode nodeD = new TreeNode();

nodeD.Tag = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

nodeD.Text = "Desktop";

nodeD.ImageIndex = 10;

nodeD.SelectedImageIndex = 10;

TreeView.Nodes.Add(nodeD);

就像上面代码展示的那样。我们需要添加地一个主节点。我的文档。我的电脑等等。然后获得子目录。

string[] dirList;
dirList = Directory.GetDirectories(parentNode.Tag.ToString());
Array.Sort(dirList);
if (dirList.Length == parentNode.Nodes.Count)
    return;
for (int i = 0; i < dirList.Length; i++)
{
    node = new TreeNode();
    node.Tag = dirList[i]; 
    node.Text = dirList[i].Substring(dirList[i].LastIndexOf(@"\") + 1);
    node.ImageIndex = 1;
    parentNode.Nodes.Add(node);
}

 

可以从下载包里看到完整的代码。我们还应该处理鼠标单击事件。

现在我们有了一个资源管理器。还有FTP和VS所需要的所有信息。

首先,我们连接服务器。我们应该怎么做呢?

FTPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
AppendText(rchLog,"Status : Resolving IP Address\n",Color.Red);
remoteAddress = Dns.GetHostEntry(Server).AddressList[0];
AppendText(rchLog, "Status : IP Address Found ->" + remoteAddress.ToString() + "\n", Color.Red);
addrEndPoint = new IPEndPoint(remoteAddress, Port);
AppendText(rchLog,"Status : EndPoint Found ->" + addrEndPoint.ToString() + "\n", Color.Red);
FTPSocket.Connect(addrEndPoint);

 

是的。我们需要一个socket连接到服务器 ,然后发送命令
AppendText(rchLog, "Command : " + msg + "\n", Color.Blue);
Byte[] CommandBytes = Encoding.ASCII.GetBytes((msg + "\r\n").ToCharArray());
FTPSocket.Send(CommandBytes, CommandBytes.Length, 0);
//read Response
ReadResponse();

我们发送命令到服务器。服务器以他自己的语言来响应。我们需要理解他。响应包括3位数字和一些解释。

 

private string SplitResponse()
{
    try
    {
        while (true)
        {
            Bytes = FTPSocket.Receive(Buffer, Buffer.Length, 0); //Number Of Bytes (Count)
            StatusMessage += Encoding.ASCII.GetString(Buffer, 0, Bytes); //Convert to String
            if (Bytes < Buffer.Length)  //End Of Response
                break;
        }
        string[] msg = StatusMessage.Split('\n');
        if (StatusMessage.Length > 2)
            StatusMessage = msg[msg.Length - 2];  //Remove Last \n
        else
            StatusMessage = msg[0];
        if (!StatusMessage.Substring(3, 1).Equals(" "))
            return SplitResponse();
        for (int i = 0; i < msg.Length - 1; i++)
            AppendText(rchLog, "Response : " + msg[i] + "\n", Color.Green);
        return StatusMessage;
    }
    catch(Exception ex)
    {
        AppendText(rchLog, "Status : ERROR. " +ex.Message+ "\n", Color.Red);
        FTPSocket.Close();
        return "";
    }
}

 

完了。现在我们可以下载,上传,重命名。或者删除了。

4 FTP命令列表

命令 描述
ABOR 中断一个活动的文件传输
ACCT 系统帐号信息
ADAT 认证/安全数据
ALLO 分配空间来接收文件
APPE 添加文件到服务器
AUTH 认证/安全机制
CCC 清除命令通道
CDUP 转到父目录
CONF 机密性保护命令
CWD 改变服务器上的工作目录
DELE 删除服务器上的指定文件
ENC 机密保护通道
EPRT 指定一个服务器应该连接的扩展地址和端口
EPSV 进入扩展的被动模式
FEAT 得到服务器提供的功能列表
HELP 返回指定命令信息
LANG 返回语言信息
LIST 如果是文件名列出文件信息,如果是目录则列出文件列表
LPRT 指定一个服务器应该连接的长地址和端口
LPSV 进入长被动模式
MDTM 返回文件最近修改时间
MIC 完整的保护命令
MKD 创建目录
MLSD 列出指定目录的内容
MLST 在命令行上列出对象的精确信息
MODE 传输模式(S=流模式,B=块模式,C=压缩模式)
NLST 列出指定目录内容
NOOP 无动作,(虚包,来自常连接中)
OPTS 选择一个功能的选项
PASS 验证密码
PASV 进入被动模式
PBSZ 保护缓冲区大小
PORT 指定服务器应该连接的地址和端口
PROT 数据通道保护级别
PWD 显示当前工作目录
QUIT 从FTP服务器上退出登录
REIN 重新初始化登录状态连接
REST 由指定点重启文件传递
RETR 传递文件副本
RMD 在服务器上删除指定目录
RNFR 从旧名称重命名
RNTO 到新名称
SITE 向远程服务器发送指定命令
SIZE 返回文件大小
SMNT 挂载指定文件结构
STAT 返回当前状态
STOR 储存(复制)文件到服务器上
STOU 储存文件到服务器指定文件上
STRU 设置结构(F=文件,R=记录,P=页面)
SYST 返回服务器使用的操作系统
TYPE 传输模式(A=ASCII,E=EBCDIC,I=binary)
USER 验证用户
XCUP 跳到当前工作路径的父目录
XMKD 新建目录
XPWD 输出当前工作目录
XRMD 删除目录

 

5 返回码列表

  • 2xx –返回成功
  • 4xx or 5xx – 返回失败
  • 1xx or 3xx – 错误或不完整的回复

第二位定义了错误的类型

  • x0z – 语法 – 有语法错误.
  • x1z – 信息 – 请求提供信息
  • x2z – 连接 – 说明控制或数据连接有问题
  • x3z – 账户认证 – 登录或者是账户认证有问题.
  • x4z – 未定义
  • x5z – 文件系统 – 可能是服务器文件系统有问题。

 

Demo 下载

C#编写FTP客户端

6 许可

本文包括源代码和文件在CPOL下授权。

 

原文地址:File-Transfer-Protocol-FTP-Client

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

posted @ 2012-10-09 09:05  lazycoding  阅读(15457)  评论(14编辑  收藏  举报