引言:

在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信大家追MM都有自己的经验的,我感觉大部分的过程肯定是——第一步: 先通过工作关系或者朋友关系等认识MM(认识FTP协议,知道FTP协议的是什么) ; 第二步: 当然了解MM有兴趣爱好了(了解FTP协议有哪些命令和工作过程)第三步:如果对方是你的菜的话,那当然要采取追求的了(就好比用了解到的FTP协议来实现一个文件上传下载器)。不过追MM好像对我来说还是比较难的了, 所以还是言归正传了,还是好好的学习我的代码吧,回到本章的内容——FTP的协议。

(注:最近想好好改进下文章的幽默程度,所以文章中会尽量以有趣的生活中的例子来表述网络编程的知识,希望可以让大家在学习知识的同时也可以获得乐趣,如果有什么地方理解不准确的还望大家多多指出。)

一、FTP协议的自我介绍

我们在上学的时候,同学们第一次开学的时候老师一般会组织大学到讲台上进行自我介绍,让同学都互相认识,同样,如果对于没有接触过FTP协议的朋友来说,FTP协议的自我介绍当然也是不可避免的了,这样我们才能进一步去了解FTP协议 “这位同学”了,之后才能和他成为好朋友,或者是好基友了。下面就开始FTP协议同学的自我介绍了, 大家热烈欢迎。

FTP 协议同学: 大家好, 我的名字叫FTP,FTP是文件传输协议(File Transfer Protocol,FTP),我的工作就是负责将文件从一台计算机传输到另外一台计算机,并且我还可以保证传输的可靠性。我的工作流程可以通过下面的一张图来表达:

从图中大家应该可以明白我的工作过程了吧,我的工作过程是典型的C/S模式——我的客户端(在本章实现的文件上传下载器属于客户端)首先发起与我的服务器连接连接,告诉我的服务器说“我现在想和你聊聊天”, 然后我的服务器收到这个请求后给出回答——“聊天,当然可以了,我批准了”,客户端收到这个信息后,就可以服务器之间就建立一条马路或者是通道,然后我的客户端好还想进一步了解下我的服务器,在发出一个说“我想要下载你上面的东西 或者是 我想上传一些文件到你那里,想让你帮我保管下,这样我可以随处都可以从你那里得到我上传的资料的”, 我的服务器收到请求后,如果允许客户端这么做的话就会回答说 “可以啊”(就像我们追女生一样,建立好关系后,当然就要表白了,此时我们就说“我很喜欢你之类的话”,然后等待MM的回答,“可以啊” 这个答案都是我们希望听到的答案的),我的客户端听到后非常开心,马上选择自己需要上传的文件或者想从服务器下载的文件找到,上传或者下载该文件的。 我还要补充一点,在访问我的FTP服务器之前必须登录,这样我的服务器才认识你,才可能会搭理你的,登录时就需要客户端提供一个用户名和密码,提供了正确的用户名和密码后就可以和我的服务器进行聊天 和请求上传或下载我服务器上的文件了; 然而我的某些服务器提供了一种匿名的方式,我的客户端不需要提供用户名和密码就可以进行聊天了,其实匿名的方式和我聊天的本质是:提供服务的公司或机构在我的服务器上建立一个公用的账户,方便那些没有提供用户名和密码的客户端与我聊天。 上面就是我的自我介绍了,谢谢大家。

二、.Net 为实现我的客户端提供了些什么?

可以说微软真是一位雷锋叔叔的,因为在他的.Net类库中提供了很多类库供我们使用,当然为实现我的客户端也提供了一些类的支持的, 现在就看看这位好人帮我们提供了哪些类来对实现一个FTP客户端程序的支持的。

这位好人通过命名空间System.Net下的FtpWebRequest类和FtpWebResponse类提供对实现FTP客户端的支持。

2.1 FtpWebRequest类

该类是WebRequest类的派生类,FTPWebRequest类用于向服务器发出请求,告诉服务器说“我想和你聊天",如果要获得FtpWebRequest的一个实例,则需要使用Create方法来创建实例,对于该类如何使用我在这里也就不一一列出来的, 大家可以查看MSDN的相关文档来了解方法的使用,并且在本专题实现的程序中也会有所介绍的,下面给出MSDN中的一个链接的:

http://msdn.microsoft.com/zh-cn/library/8exfzxft.aspx

2.2 FtpWebResponse类

FTP客户端既然发话了,服务器当然也要有所表示的了, 不要哑巴一样不说话的,总要给个答复的,FtpWebResponse类就负责封装FTP服务器对客户端请求的回答的一个类。FTP客户端通过GetResponse方法来获得FtpWebResponse类的对象的,如果服务器回答说“我们可以聊天的”,这样就说明他们俩就可以互相沟通了,就好比追MM的时候你问MM说“可以给电话号码给我吗?”,然后MM对你也有好感就告诉你一个号码后,得到MM的号码也就和MM建立了沟通的通道了,就好比服务器回答“我们可以聊天的”。之后客户端和服务器就可以进行进一步的沟通(上传文件到服务器或者要求服务器给些文件给客户端),之后的过程就好比你可以通过电话号码和MM进一步的交流,知道MM的有些什么性格和爱好的。下面提供一个MSDN中该类的使用链接,这里我就不一一介绍他的成员了,大家可以到MSDN中查看的,上面每个属性和方法都有一个比较好的解释,并且大家也可以通过下面实现的FTP客户端程序进一步了解该类的使用:

http://msdn.microsoft.com/zh-cn/library/system.net.ftpwebresponse.aspx

三、如何实现一个FTP客户端程序?——看完下面的介绍你就会知道了

通过FTP协议的自我介绍部分大家应该可以明白了FTP协议的工作过程的,然而一个FTP客户端程序就是基于FTP协议的文件上传下载器,通过这个程序大家可以对FTP服务器上的资料进行浏览、上传和下载等操作的。

程序中主要模块的代码:

登录模块:

View Code

  #region 登录模块的实现// 登录服务器事件private void btnlogin_Click(object sender, EventArgs e){if (tbxServerIp.Text == string.Empty){MessageBox.Show("请先填写服务器IP地址", "提示");return;}ftpUristring = "ftp://" + tbxServerIp.Text;networkCredential = new NetworkCredential(tbxUsername.Text, tbxPassword.Text);if (ShowFtpFileAndDirectory() == true){btnlogin.Enabled = false;btnlogout.Enabled = true;lstbxFtpResources.Enabled = true;lstbxFtpState.Enabled = true;tbxServerIp.Enabled = false;if (chkbxAnonymous.Checked == false){tbxUsername.Enabled = false;tbxPassword.Enabled = false;chkbxAnonymous.Enabled = false;}else{chkbxAnonymous.Enabled = false;}tbxloginmessage.Text = "登录成功";btnUpload.Enabled = true;btndownload.Enabled = true;btnDelete.Enabled = true;}else{lstbxFtpState.Enabled = true;tbxloginmessage.Text = "登录失败";}}// 显示资源列表private bool ShowFtpFileAndDirectory(){lstbxFtpResources.Items.Clear();string uri = string.Empty;if (currentDir == "/"){uri = ftpUristring;}else{uri = ftpUristring + currentDir;}string[] urifield = uri.Split(' ');uri = urifield[0];FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.ListDirectoryDetails);// 获得服务器返回的响应信息FtpWebResponse response = GetFtpResponse(request);if (response == null){return false;}lstbxFtpState.Items.Add("连接成功,服务器返回的是:"+response.StatusCode+" "+response.StatusDescription);// 读取网络流数据Stream stream = response.GetResponseStream();StreamReader streamReader = new StreamReader(stream,Encoding.Default);lstbxFtpState.Items.Add("获取响应流....");string s = streamReader.ReadToEnd();streamReader.Close();stream.Close();response.Close();lstbxFtpState.Items.Add("传输完成");// 处理并显示文件目录列表string[] ftpdir = s.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);lstbxFtpResources.Items.Add("↑返回上层目录");int length = 0;for (int i = 0; i < ftpdir.Length; i++){if (ftpdir[i].EndsWith(".")){length = ftpdir[i].Length - 2;break;}}for (int i = 0; i < ftpdir.Length; i++){s = ftpdir[i];int index = s.LastIndexOf('\t');if (index == -1){if (length < s.Length){index = length;}else{continue;}}string name = s.Substring(index + 1);if (name == "." || name == ".."){continue;}// 判断是否为目录,在名称前加"目录"来表示if (s[0] == 'd' || (s.ToLower()).Contains("<dir>")){string[] namefield = name.Split(' ');int namefieldlength = namefield.Length;string dirname;                   dirname = namefield[namefieldlength - 1];// 对齐dirname = dirname.PadRight(34,' ');name = dirname;// 显示目录lstbxFtpResources.Items.Add("[目录]" + name);}}for (int i = 0; i < ftpdir.Length; i++){s = ftpdir[i];int index = s.LastIndexOf('\t');if (index == -1){if (length < s.Length){index = length;}else{continue;}}string name = s.Substring(index + 1);if (name == "." || name == ".."){continue;}// 判断是否为文件if (!(s[0] == 'd' || (s.ToLower()).Contains("<dir>"))){string[] namefield = name.Split(' ');int namefieldlength = namefield.Length;string filename;filename = namefield[namefieldlength - 1];// 对齐filename = filename.PadRight(34, ' ');           name = filename;// 显示文件
                    lstbxFtpResources.Items.Add(name);}}return true;}// 注销事件private void btnlogout_Click(object sender, EventArgs e){btnlogin.Enabled = true;btnlogout.Enabled = false;tbxServerIp.Enabled = true;tbxServerIp.SelectAll();tbxServerIp.Focus();chkbxAnonymous.Enabled = true;if (chkbxAnonymous.Checked == false){tbxUsername.Enabled = true;tbxPassword.Enabled = true;}tbxloginmessage.Text = "你已经退出了。";lstbxFtpResources.Items.Clear();lstbxFtpResources.Enabled = false;lstbxFtpState.Items.Clear();lstbxFtpState.Enabled = false;btnUpload.Enabled = false;btndownload.Enabled = false;btnDelete.Enabled = false;}#endregion

对FTP服务器操作模块(本程序中实现下载、上传和删除的功能):

View Code

  #region 对文件的操作模块实现// 上传文件到服务器事件private void btnUpload_Click(object sender, EventArgs e){// 选择要上传的文件OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.FileName = openFileDialog.FileNames.ToString();openFileDialog.Filter = "所有文件(*.*)|*.*";if (openFileDialog.ShowDialog() != DialogResult.OK){return;}FileInfo fileinfo = new FileInfo(openFileDialog.FileName);try{string uri = GetUriString(fileinfo.Name);FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.UploadFile);request.ContentLength = fileinfo.Length;int buflength = 8196;byte[] buffer = new byte[buflength];FileStream filestream = fileinfo.OpenRead();Stream responseStream = request.GetRequestStream();lstbxFtpState.Items.Add("打开上传流,文件上传中...");int contenlength = filestream.Read(buffer, 0, buflength);while (contenlength != 0){responseStream.Write(buffer, 0, contenlength);contenlength = filestream.Read(buffer, 0, buflength);}responseStream.Close();filestream.Close();FtpWebResponse response = GetFtpResponse(request);if (response == null){lstbxFtpState.Items.Add("服务器未响应...");lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;}lstbxFtpState.Items.Add("上传完毕,服务器返回:" + response.StatusCode + " " + response.StatusDescription);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show("上传成功!");// 上传成功后,立即刷新服务器目录列表
                ShowFtpFileAndDirectory();}catch (WebException ex){lstbxFtpState.Items.Add("上传发生错误,返回信息为:" + ex.Status);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, "上传失败");}}private string GetUriString(string filename){string uri = string.Empty;if (currentDir.EndsWith("/")){uri = ftpUristring + currentDir + filename;}else{uri = ftpUristring + currentDir + "/" + filename;}return uri;}// 从服务器上下载文件到本地事件private void btndownload_Click(object sender, EventArgs e){string fileName = GetSelectedFile();if (fileName.Length == 0){MessageBox.Show("请选择要下载的文件!","提示");return;}// 选择保存文件的位置SaveFileDialog saveFileDialog = new SaveFileDialog();saveFileDialog.FileName = fileName;saveFileDialog.Filter = "所有文件(*.*)|(*.*)";if (saveFileDialog.ShowDialog() != DialogResult.OK){return;}string filePath = saveFileDialog.FileName;try{string uri = GetUriString(fileName);FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.DownloadFile);FtpWebResponse response = GetFtpResponse(request);if (response == null){lstbxFtpState.Items.Add("服务器未响应...");lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;}Stream responseStream = response.GetResponseStream();FileStream filestream = File.Create(filePath);int buflength = 8196;byte[] buffer = new byte[buflength];int bytesRead =1;lstbxFtpState.Items.Add("打开下载通道,文件下载中...");while (bytesRead != 0){bytesRead = responseStream.Read(buffer, 0, buflength);filestream.Write(buffer, 0, bytesRead);}responseStream.Close();filestream.Close();lstbxFtpState.Items.Add("下载完毕,服务器返回:" + response.StatusCode + " " + response.StatusDescription);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show("下载完成!");}catch (WebException ex){lstbxFtpState.Items.Add("发生错误,返回状态为:" + ex.Status);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, "下载失败");}}// 获得选择的文件// 如果选择的是目录或者是返回上层目录,则返回nullprivate string GetSelectedFile(){string filename = string.Empty;if (!(lstbxFtpResources.SelectedIndex == -1 || lstbxFtpResources.SelectedItem.ToString().Substring(0, 4) == "[目录]")){string[] namefield = lstbxFtpResources.SelectedItem.ToString().Split(' ');filename = namefield[0];}return filename;}// 删除服务器文件事件private void btnDelete_Click(object sender, EventArgs e){string filename = GetSelectedFile();if (filename.Length == 0){MessageBox.Show("请选择要删除的文件!", "提示");return;}try{string uri = GetUriString(filename);if (MessageBox.Show("确定要删除文件 " + filename + " 吗?", "确认文件删除", MessageBoxButtons.YesNo) == DialogResult.Yes){FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.DeleteFile);FtpWebResponse response = GetFtpResponse(request);if (response == null){lstbxFtpState.Items.Add("服务器未响应...");lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;}lstbxFtpState.Items.Add("文件删除成功,服务器返回:" + response.StatusCode + " " + response.StatusDescription);ShowFtpFileAndDirectory();}else{return;}}catch (WebException ex){lstbxFtpState.Items.Add("发生错误,返回状态为:" + ex.Status);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, "删除失败");}}#endregion

由于程序的演示效果需要结合下一专题介绍的FTP服务器,具体的演示效果大家可以查看——专题十二:实现一个简单的FTP服务器,下面就列出程序的主界面截图:

四、小结

这个专题的介绍就到这里的,在下一个专题将和大家介绍下如何实现一个FTP服务器,这样再加上本专题制作的FTP文件上传下载器就可以形成一个完整的软件套件,自己实现FTP文件上传下载器访问自己实现的FTP服务器将会让大家觉得很很有趣的, 想赶快体验下这样的一种乐趣吗?那就赶快下载本专题的源码来亲身体验下吧。通过希望通过本专题让大家对FTP协议不再陌生,并且做Asp.net开发的朋友,文件的上传和下载是一个公共模块的,然后Asp.net中的文件上传和下载只是通过浏览器向HTTP服务器发送HTTP命令,来告诉HTTP服务器说“我想和你对话”,“我想要你上面的某某文件”以及“我想上传一个文件到你的上面去”等等的对话,这个系列完成之后,我也会和大家总结下网络编程的知识的。

[C# 网络编程系列]专题十一:实现一个基于FTP协议的程序——文件上传下载器...相关推荐

  1. 网络编程应用:基于TCP协议【实现文件上传】--练习

    要求: 基于TCP协议实现一个向服务器端上传文件的功能 客户端代码: package Homework2;import java.io.File; import java.io.FileInputSt ...

  2. [C# 网络编程系列]专题十二:实现一个简单的FTP服务器

    引言: 休息一个国庆节后好久没有更新文章了,主要是刚开始休息完心态还没有调整过来的, 现在差不多进入状态了, 所以继续和大家分享下网络编程的知识,在本专题中将和大家分享如何自己实现一个简单的FTP服务 ...

  3. 【Java编程系列】Minio实现文件上传下载

    热门系列: [Java编程系列]Amazon S3实现文件上传下载 目录 热门系列: 1.前言 2.Minio实战代码 2.1 Minio环境部署 2.2 Minio的Sdk对接实现 2.2.1 Mi ...

  4. Python3之socket编程(TCP/UDP,粘包问题,数据传输、文件上传)

    一.socket的定义 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后 ...

  5. FTP编程实验——实现文件上传下载(基于Python3.7和PyQt5)

    目录 FTP编程实现文件上传下载(基于Python3.7和PyQt5) 一.实验目的 二.实验内容 三.实验步骤 (一)服务器端 (二)客户端 [1] 界面设计 [2] 生成布局代码 [3] 功能实现 ...

  6. 通过威纶通触摸屏的穿透功能实现对FX3U系列PLC程序的上传下载和监控的具体方法

    通过威纶通触摸屏的穿透功能实现对FX3U系列PLC程序的上传下载和监控的具体方法 由于FX3U系列PLC本体只有一个通信接口,如果和威纶通触摸屏连接后,此时就无法用电脑监控调试程序了,非常的不方便. ...

  7. antd的联级选择器异步调用编辑回显_react-uplod-img 是一个基于 React antd组件的图片上传组件...

    react-uplod-img 是一个基于 React antd组件的图片上传组件 支持oss qiniu等服务端自定义获取签名,批量上传, 预览, 删除, 图片精确的尺寸限制 排序等功能 需要 re ...

  8. [C# 网络编程系列]专题九:实现类似QQ的即时通信程序

    引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的.为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在 ...

  9. [C# 网络编程系列]专题十:实现简单的邮件收发器

    引言: 在我们的平常工作中,邮件的发送和接收应该是我们经常要使用到的功能的.因此知道电子邮件的应用程序的原理也是非常有必要的,在这一个专题中将介绍电子邮件应用程序的原理.电子邮件应用程序中涉及的协议和 ...

最新文章

  1. 计算类class的sizeof大小
  2. webpack 处理CSS
  3. 我的数字万用表怎么了?
  4. hihoCoder #1445 : 后缀自动机二·重复旋律5
  5. 应该怎么做一个登录功能?
  6. asp.net core 腾讯验证码的接入
  7. 给定有权无向图的邻接矩阵如下,求其最小生成树的总权重,代码。
  8. 动态规划——0-1背包问题
  9. 基于JAVA+Servlet+JSP+MYSQL的学生宿舍卫生评分系统
  10. 水晶报表下将数字转换成金额大写的公式
  11. 2013第41周三余生最年青的时候
  12. 基于springboot的民办职业学校缴费系统
  13. linux中at重定位命令,readelf命令_Linux readelf 命令用法详解:用于显示elf格式文件的信息...
  14. 【Axure】web端数据可视化设计(数据统计,数据大屏)
  15. php如何配置gii,PHP Framework YII的里的gii設置。
  16. OCM_第二天课程:Section1 —》配置 Oracle 网络环境
  17. 函数的基本使用,切克闹
  18. Vue脚手架创建步骤
  19. 2010年SQLite学习笔记之一
  20. 电脑不小心被格式化了 里面的应用软件如何恢复?

热门文章

  1. c语言数组的一维编程,【C语言】转换一维数组
  2. linux脚本查看变量类型,Shell变量:Shell变量的定义、删除变量、只读变量、变量类型...
  3. linux能远程打开桌面版,如何从Linux上远程显示Windows桌面
  4. nginx win 启动关闭_windows下Nginx启动、关闭、重启bat工具
  5. php判断邮箱是否合法性,php验证邮箱地址合法性
  6. 万字大白话带你重拾JVM
  7. 不愧是摸鱼高手Python matplotlib 绘制频谱图都会,能怪老板不管
  8. java range对象_Java LocalTime range()用法及代码示例
  9. 混合mixin函数_Less 混合
  10. 计算机网络有限制,计算机网络中软件限制策略的应用规则有哪些