鉴于上一篇POST过于抽象以至于很多人无法理解,现在用代码来说话,我们一起来重新回顾一下事故现场的情况。
首先在本机安装FTP软件,我这里使用的Serv-U一个用得非常广泛的Ftp Server,准备好Ftp的目录,我这里使用自己放mp3的目录
其中有一个子目录 2
我们可以看到两个目录的内容截然不同以方便我们重现事故现场。
第二部我们建立一个Winform项目
之后在界面上用三个按钮来实现testCase
第三步是准备的重头戏,我们准备一个Ftp的操作类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
namespace TestFtpWebRequest
{
class FtpHelper
{
public static void Upload(string Url, string LocalPath)
{
FileInfo f = new FileInfo(LocalPath);
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(Url + "/" + f.Name);
req.Credentials = new NetworkCredential("Test", "123456");
req.Method = WebRequestMethods.Ftp.UploadFile;
req.UseBinary = true;
req.ContentLength = f.Length;
FtpWebResponse rep = (FtpWebResponse)req.GetResponse();
using (Stream s = req.GetRequestStream())
{
using (FileStream fs = f.OpenRead())
{
int readcount = 0;
long totalread = 0;
byte[] buffer = new byte[1024];
while (true)
{
readcount = fs.Read(buffer, 0, 1024);
totalread += readcount;
s.Write(buffer, 0, readcount);
if (totalread >= f.Length)
{
break;
}
}
}
}
}
public static string[] List(string Url)
{
List<string> rs = new List<string>();
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(Url);
req.Credentials = new NetworkCredential("Test", "123456");
req.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse rep = (FtpWebResponse)req.GetResponse();
long len = rep.ContentLength;
using (Stream s = rep.GetResponseStream())
{
MemoryStream ms = new MemoryStream();
int readcount = 0;
long totalcount = 0;
byte[] buffer = new byte[1024];
while (true)
{
readcount = s.Read(buffer, 0, 1024);
totalcount += readcount;
ms.Write(buffer, 0, readcount);
if (totalcount >= len)
{
break;
}
}
s.Close();
rep.Close();
string str = Encoding.Default.GetString(ms.ToArray());
StringReader sr = new StringReader(str);
string line = string.Empty;
while ((line = sr.ReadLine()) != null)
{
rs.Add(line);
}
}
return rs.ToArray();
}
}
}
<!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com -->
这里准备了两个操作方法,一个是读取文件列表,一个是上传文件
最后在按钮里写上调用的方法
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestFtpWebRequest
{
public partial class Form1 : Form
{
const string Path1 = @"D:\MyDocument\test.jpg";
const string Path2 = @"D:\MyDocument\yoxi.jpg";
const string FtpUrl = "ftp://192.168.212.102";
const string FtpUrl2 = "ftp://192.168.212.102/2";
public Form1()
{
InitializeComponent();
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Text = string.Empty;
string[] files = FtpHelper.List(FtpUrl);
textBox1.Text = "file count:" + files.Length + "\r\n";
foreach (string s in files)
{
textBox1.Text += "ftp:" + s + "\r\n";
}
}
private void button1_Click(object sender, EventArgs e)
{
FtpHelper.Upload(FtpUrl2, Path1);
MessageBox.Show("up ok!");
}
private void button2_Click(object sender, EventArgs e)
{
FtpHelper.Upload(FtpUrl2, Path2);
MessageBox.Show("up ok!");
}
}
}
<!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com -->
好了,根据两个ftp的方法大家可以看到,从表面上两个方法应该是独立的,不管在什么时候,我如果按列表的按钮都应该返回Ftp根目录的文件列表出来。但是实际的执行结果,我们拭目以待。
首先我们执行程序,点击列表按钮(List with no upload),这个时候我们能够看到返回的确实是根目录的文件
现在我们继续点击 FirstUpload,按钮,猜猜结果怎么样? 报错了:
路径明明是对的,为什么报错?大家可以自己想想
接下来我们把顺序换一下。重新执行程序,这次先点击Firstupload,结果上传成功,结果如下
好,这个时候我们再点击列表按钮,本来应该显示根目录内容的,结果却显示的:
这下看明白了没?好的,接下来我们调整一下Ftp的设置,现在Ftp账号的设置如下:
我们现在把将用户锁定于主目录的勾去掉:
如此这般,好了,现在我们再次执行程序。
先点击列表,然后再点击上传,看看,没报错,成功了:
---------------------------------------------------------
一开始我怀疑是因为KeepAlive保持了链接造成的,因为这个结果非常像是每一个Request都复用了连接,所以我两个方法都加上了KeepAlive=false
然后恢复Serv-U的设置,将锁定用户于主目录的勾选上。
执行程序,点击列表,再点击上传,成功了,貌似没问题了吧。不过不要高兴得太早,这个时候再点击一次列表,看,报错了:
到现在为止,我应该对事故的由来,前因后果说得很清楚了。
这里我总结出了几点问题。
1.不管是不是要复用底层的链接,但是在语义上的一致性是需要保证的,一个Request,既然用url :Ftp://ip/创建出来的,那么就应该是操作Ftp的根而不是其他目录,如果这个都不能保证,那么谁还能信任这样的一个工具?更不用说多线程的环境下工作会如何了。
2.为了安全性,大部分ftp都会锁定用户到主目录,一个ftpclient怎么能够依赖于服务端的设置工作?无论是谁做出这种脑残设定都是不对的。
3.KeepAlive禁用后,居然同样的过程执行都会报错,不可理喻。
具体问题处在哪里,等我下次分析了。
分享到:
相关推荐
### 实现FTP方法FtpWebRequest 在现代软件开发过程中,文件传输协议(FTP)仍然是一个常用的技术手段,尤其是在需要在不同系统之间交换文件时。本文将深入探讨如何使用C#中的`FtpWebRequest`类来实现FTP的基本操作...
在.NET框架中,`FtpWebRequest`类是用于与FTP(文件传输协议)服务器进行交互的重要工具。这个类提供了一种方便的方式,让我们能够执行各种FTP操作,如上传、下载、列出目录内容以及删除文件等。下面将详细介绍如何...
C# 实现 FTP 方法(一)- FtpWebRequest 本文档主要讲解了使用 C# 语言实现 FTP 方法的第一部分,重点介绍了使用 FtpWebRequest 类实现 FTP 连接、文件上传和下载、文件列表获取等操作。 FTP 连接 在 FTP_Class ...
Dim request As FtpWebRequest = DirectCast(WebRequest.Create("ftp://your_ftp_server/your_file_path"), FtpWebRequest) request.Credentials = New NetworkCredential("username", "password") request.Method =...
FtpWebResponse FtpWebRequest
Dim request As FtpWebRequest = DirectCast(WebRequest.Create("ftp://your_server/your_directory"), FtpWebRequest) request.Credentials = New NetworkCredential("username", "password") ``` **创建FTP目录**...
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUrl + "/" + remotePath); request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; request.Credentials = new NetworkCredential...
2. 设置FtpWebRequest的Method属性,指定使用的FTP协议方法的类型 3. 设置FtpWebRequest的Credentials属性,指定用户名和密码 4. 发出请求 5. 接收响应数据流 6. 关闭流 二、FtpWebRequest类 FtpWebRequest类是...
2. **获取目录列表**:通过FtpWebRequest发送请求并获取响应,然后使用FtpWebResponse的GetResponseStream方法读取响应流。这个流包含服务器返回的目录列表,通常是一个ASCII文本,我们需要解析它来提取文件和子目录...
2、示例了ftp的上传功能。创建一个指向某ftp服务器的FtpWebRequest对象,然后设置其不同的属性Credentials,KeepAlive,Method,UseBinary,ContentLength。打开本地机器上的文件,把其内容写入ftp请求流。
2. 设置上传文件流:接着,我们需要将要上传的文件读取为字节流,并设置到FtpWebRequest对象的GetRequestStream()方法中。 ```csharp using (FileStream fileStream = File.OpenRead("本地文件路径")) { byte[] ...
在FTP-LS2的实现中,C#的System.Net命名空间中的FtpWebRequest和FtpWebResponse类是关键,它们提供了FTP协议的低级接口。开发者可以使用这些类来构造请求,如登录、改变工作目录、列出目录内容、上传和下载文件等。 ...
using (FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri($"ftp://{remoteHost}/{remotePath}/{remoteFilePath}"))) { request.Method = WebRequestMethods.Ftp.UploadFile; request....
在C#中,我们可以利用System.Net命名空间中的FtpWebRequest和FtpWebResponse类来实现FTP客户端的功能,而创建FTP服务器则通常需要自定义编程。下面将详细讨论C#中实现FTP的相关知识点。 1. FTP基础: FTP是一个基于...
1. **创建FtpWebRequest实例**:通过调用`FtpWebRequest.Create(Uri)`方法创建一个指向指定FTP地址的请求对象。 ```csharp FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://ftp.nuaa....
2. 设置`FtpWebRequest`的属性,如`UseBinary`(设置为true表示二进制模式,适用于大多数文件)和`ContentType`(一般设置为"application/octet-stream")。 3. 使用`GetRequestStream()`方法获取上传流,然后通过该...
4. **设置上传速度和超时**:可以通过`FtpWebRequest.ServicePoint.ConnectionLimit`控制并发连接数以提高上传速度,同时设置`FtpWebRequest.Timeout`和`FtpWebRequest.KeepAlive`属性以防止因超时或无响应导致的...
2. VB中的FTP组件: - 在VB6及更早版本中,我们可以使用Winsock控件或MSFTPSVC组件来实现FTP功能。 - 在.NET Framework环境下,可以使用System.Net.FtpWebRequest和System.Net.FtpWebResponse类。 3. FTP连接: ...
2. 设置FTP操作: 你可以通过`request.Method`属性设置执行的操作,例如下载(`WebRequestMethods.Ftp.DownloadFile`)、上传(`WebRequestMethods.Ftp.UploadFile`)等。 3. 设置连接属性: - `Credentials`: ...