从 Windows CE 5.0 设备进行 FTP






4.75/5 (8投票s)
Windows CE 设备并未针对 FTP 的使用进行正确设置,尽管存在 HttpWebRequest 和 HttpWebResponse 类。
引言
在行业中,仍在使用许多带有条形码扫描仪的手持设备。使用 Windows CE 5.0,可以为这些设备编程应用程序,这些设备的技术在十年前是主流。我的一个客户正在使用这些设备在建筑物外部扫描条形码。在 SQL Compact 中注册他的数据时,他不想使用同步框架将数据导入中央系统。他使用 FTP。而 FTP 在 Compact .NET Framework 中的支持并不完善。Microsoft 提供了一个解决方案,使用 HttpWebRequest
将文件发送到中央系统。但是,NAS 回复我“405 Method not Allowed”。之后,我使用了 OpenNet CF DLL 来使用 FtpRequest
。看起来文件已发送,但在 NAS 上未收到任何数据。尽管有日志文件,但未发现任何错误。在遇到这些障碍后,我决定使用 TcpClient
发送文件。这简直是完美运行。本文仅描述了基本的 FTP 发送。请阅读源代码中的注释。
还有一件事。Visual Studio 2008 是创建此类移动应用程序的最新版本。VS 2013 中存在可能性,但我还没有( yet)该版本的许可证。
背景
TcpClient
允许您通过 TCP/IP 协议创建与其他客户端的连接。在这种情况下,您可以创建自己的 FTP 客户端来发送文件。这是一种低级别的解决方案,但需要程序员了解 FTP。实际上,这是一个问答系统。此外,Compact Framework 支持
event Action<someObject> SomeEventAFormCanSubScribeToEvent;
因此,一个接口可以描述事件,并且可以通过该类来触发它,而窗体仅需要接收到的对象来更新其窗体对象。
由于 Compact Framework 2.0 的限制,FTP 在 Framework 中的集成程度不如新 Framework。通过在代码中编写 FTP 功能,您可以实现文件的发送。
Using the Code
当您使用此代码时,您将能够连接到 FTP 服务器并向其发送文件。您可以设置“用户名”和“密码”进行连接,但也可以注释掉这些行。程序中会检查您的设备是否可以连接到 PPP_Peer 协议,否则您将无法访问 FTP 服务器。
入门
在此示例中,一个简单的窗体包含
- 带有文本“文件进度”的
Label
- 显示已发送文件数量的
ProgressBar
- 显示来自 FTP 服务器响应的
Label
- 带有文本“文件”的
Label
- 将显示待发送文件名的
ListBox
。ListBox
是ReadOnly
的。在传输文件的过程中,已传输的文件会在列表中被选中。 - 带有“
Start
”文本的Button
。如果ListBox
包含多于 0 行并且可以找到 PPP_Peer,则该按钮为 Enabled。 实例化接口 IFtpClient
,并使用可用命令传输文件以及从文件获取事件更新。
窗体监听以下事件。
FtpProgressEvent
:包含一个FtpProgress
业务对象,其中包含当前正在传输文件的数据。RetrieveFileListEvent
:获取一个FileInfo[]
对象,其中包含可以发送的文件。SendFinishedEvent
:接收一个String
消息,在所有文件传输完成后显示在消息框中。
FtpClient
类使用 FTPHelper
类和 IFtpClient
接口。在 FtpClient
类中,您会找到 3 个方法
public GetLocalFiles
:此方法设置一个FileInfo[]
对象,其中包含可用文件,并触发RetrieveFileListEvent
事件。public SendFiles()
:将FileInfo[]
对象中的文件发送出去的方法。private FtpClient_FtpCurrentProgressEvent(
:此方法监听FtpProgress
ftpProgress)FTPHelper
类中的FtpCurrentProgressEvent
事件;该事件在FtpClient
类的构造函数中设置。此方法设置FtpProgressEvent
,以便窗体更新其控件。
该类有一个名为 ActiveSyncConnectionEnabled
的只读属性。该属性可以告知设备是否可以通过 FTPHelper
类中的 Boolean
ActiveSyncConnected
连接到 FTP 服务器。
在 FTPHelper
类中,您会找到 5 个方法
SendFTPCommand(
:将带有必需动词 (verb(s)) 的命令写入String
Command,String
Verb,String
Verb2)StreamWriter
CreatePassiveFtpSocketInformation()
:在发送文件时,会使用 PASV 命令。响应会返回一个string
,必须将其转换为带有端口号的IPEndPoint
。ReadLineFromStream()
:将命令写入StreamWriter
后,读取响应流。此响应会发送到FtpCurrentProgressEvent
事件。ReadAllBytesFromTheFile(
:读取将要发送到 FTP 服务器的文件的字节。FileInfo
file)StartCurrentProgressEvent()
:通过FtpClient
类将当前FtpProgress
业务对象发送到窗体的方法。
业务对象
源文件中包含 2 个业务对象
FtpPassiveConnection
:包含被动 IP 地址和被动端口号public IPAddress PassiveIP; public Int32 PasssivePortNr;
FtpProgress
:包含有关当前正在传输文件的信息以及用于ProgressBar
的信息public Int32 CurrentFileNr; // after sending each file Iterate +1. The selectedIndex of the ListBox will reflect the current file in sending public Int32 LastFileNr; // needed for the Maximum property for the ProgressBar public String FileName; // name of the current file name public Int64 FileBytes; // the number of bytes to be send. When streaming in parts a file progress can be shown (2nd progress bar needed) public Int64 SendFileBytes; // number of bytes send public String FtpResponse; // current FtpReponse
有一个名为 IOHelpers
的辅助类,它在应用程序中填充 FileInfo[]
对象。
有一个用于基本异常处理的类 ExceptionHandling.ShowMessage
。它会显示一个 MessageBox
,其中包含发生的异常。
TcpClient 的基本信息
当您在 Compact Framework 中使用 TcpClient
时,您不会发现它与 2.0 框架有任何区别。请在此处 查看。您可以通过声明轻松使用 TcpClient
类:
TcpClient client = new TcpClient();
// in this case the next line will be
client.Connect(servername, port); // servername = String, port is Int32
或
TcpClient client = new TcpClient(servername, port); // servername = String, port is Int32
请注意,您也可以使用 IPEndPoint
进行连接。请在此处 查看。
TcpClient
使用 IDisposable
,因此建议使用
using (TcpClient client = new TcpClient(servername, port))
{
// code here
}
FTP 基本知识
一些 FTPServers
有多行欢迎消息。因此,如果只读取一行,客户端就会滞后。FileZille 服务器的欢迎消息有 3 行。但是如何在 FTP 应答中检测是否正在处理多行?FTP 服务器的应答始终以 3 位数字开头。在这 3 位数字之后,您会看到一个 - 或一个 <空格>。当您看到空格时,您就知道您已到达服务器应答的最后一行。 在代码中
protected void ReadLineFromStream()
{
bool MultipleLines = false;
while (true)
{
string line = rdStrm.ReadLine();
MultipleLines = line.Substring(3, 1).Equals("-");
ftpProg.FtpResponse = line;
StartCurrentProgressEvent();
if (!MultipleLines) break;
}
}
关注点
TcpClient
对于今天仍在使用的旧通信技术非常有用。
历史
- 2014 年 4 月 15 日
- 初始文章
- 2014 年 4 月 25 日
- 修复了
NULL
引用异常 - 读取流中的所有行,而不是一次一行
- 修复了
- 2015 年 4 月 30 日
- 解决了使用线程启动文件 FTP 发送所引起的
Control.Invoke
异常。现在已创建为非线程。
- 解决了使用线程启动文件 FTP 发送所引起的