IFS - 基于 Web 服务和 P2P 技术的 Internet 文件系统实现





5.00/5 (36投票s)
2002年9月20日
27分钟阅读

356198

4438
从头开始构建 Internet 文件系统 - 使 Web 服务和 P2P 技术协同工作以构建虚拟文件系统
- 下载源代码和本文 - 205 KB
- 最新的源代码和更新的文档(将)很快在这里提供。
本页内容
简介
你可能见过Napster、Gnucleus、Morpheus等文件共享应用程序。如果你没有见过,我确信你听说过激动人心的点对点(P2P)技术。我毫不怀疑你已经看到了Web服务的大肆宣传,但你可能没有见过比HTML屏幕抓取Web服务更智能的东西,或者一个将某些专有技术或软件暴露给网络大众的Web服务。
本文演示了一个基于P2P和Web服务的虚拟文件系统,我谦虚地称之为“互联网文件系统”或IFS。不幸的是,过长的文章看起来不好,所以我将向你展示如何使用我编写的库,如果你很聪明(我知道你很聪明),你将从源代码中获取其余部分。祝你阅读愉快...
什么是互联网文件系统?
互联网文件系统是一个假想的文件系统。一个真正的互联网文件系统很难存在,因为世界各地散布着各种各样的硬件和软件平台(操作系统)。IFS通过一个中央存储库模拟文件系统,该存储库包含由众多计算机(称为对等体)发布的文件夹和文件链接(快捷方式)。对等体在存储库中共享文件和文件夹,但并不实际使用它来存储文件内容。它们而是相互通信,以在它们之间下载(复制)文件。
IFS架构
在这个简单的实现中,存储库由对等体通过Web服务(IFSWS)管理,点对点通信由P2P框架库(P2PLIB)处理。由于直接使用Web服务和P2P框架的复杂性,我构建了一个独立的P2P服务器(P2PSRV),它在对等计算机上运行并自动处理所有P2P通信。此外,为了隐藏IFS实现的细节,我在IFSWS和P2PLIB之上构建了一个互联网文件系统库(IFSLIB),它暴露了一个易于使用的对象模型来操作中央存储库,以及在对等体之间轻松复制(下载)文件。

如上图所示,这里有两个主要部分:IFS Web服务和对等体
IFS Web服务
它只负责存储和检索信息——它只是作为一个存储库。实际上,它注册/注销/登录对等体,发布文件夹和文件,检索有关对等体的关键信息等,但IFS最酷的部分是由库完成的。
对等体
我不是英语母语者,我是保加利亚人。这就是为什么我无法准确解释对等体是什么。在我的词典中,“peer”一词作为名词只有一个意思,它不是“连接到互联网的PC,可以使用某种通信协议直接与其他PC通信”。然而,这正是我在本文中赋予peer的含义。
有3样东西使这些“傻瓜”PC成为对等体——它们是P2P库、P2P服务器和IFS库。IFSLIB工作在Web服务之上,P2P服务器工作在库之上。
人们可以使用IFS库构建各种P2P应用程序——基于GUI的类似Windows资源管理器的IFS浏览器,用于自动/定时下载文件的控制台工具等。我开始开发一个IFS浏览器,但由于时间有限(我开始撰写这篇文章是为了参加网络竞赛),未能完成。然而,我在源代码中包含了这个简化版演示,所以任何喜欢这个想法(并且会C#编码)的人都可以完成(或重写)它。(现在,当我两周后更新这篇文章时,IFSBrowser的状态没有改变。那是因为我认为至少对我来说,修复bug和向库添加功能具有更高的优先级。)
为什么这个IFS很(或可能)酷?
嗯,当你需要从一个对等体复制文件到另一个对等体时,有3种情况。为了避免赘述,让我们将想要下载文件的对等体命名为P1,并将所有者对等体命名为P2。
- 两个对等体都不在防火墙后面
- P2在防火墙后面
- 两个对等体都在防火墙后面
没问题。P1从P2拉取文件
哎呀!P1无法轻易连接到P2。那么它能做什么呢?它可以执行一个Web服务方法,该方法将分配一个任务给P2,让P2将文件推送到P1。P2的PC上的P2P服务器被安排使用Web服务检索其任务。当它获得推送任务时,它连接到P1并推送文件。这容易吗?是的,我几乎实现了这个功能。
耶!我们现在该怎么办?好吧,如果P1可以给P2分配一个上传任务,那么P2可以使用Web服务将文件上传到Web服务的服务器PC。当P2完成时,它可以给P1分配一个下载任务,然后P1就会下载文件!瞧!这个功能完全没有实现,但非常容易实现。然而,由于我被一个DEADline逼得太紧了,所以我不能保证下周能实现它...
它是如何工作的?
什么如何工作?:) 好的,我将努力集中精力告诉你库是如何工作的。我不会讨论基本功能如何工作,即对等体注册、登录、文件夹和文件发布等。这些只是通过IFS Web服务在数据库中的条目。我将向你展示在两种更简单的场景中,即“没有防火墙”和“所有者在防火墙后面”的情况下,典型的文件下载是如何工作的。因为我知道你们很聪明(而且我太懒了:),我没有画任何图片,所以请继续阅读...
没有防火墙
我将再次使用P1和P2来表示感兴趣的对等体和所有者对等体。P1有一个`IfsFile`实例(参见下面的库对象),并调用`Download`方法。`IfsFile`对象有一个`OwnerPeer`属性,它返回一个`IfsPeer`实例。后者有一个`IpEndPoint`属性,包含远程对等体的IP地址和端口。此时,IFS库向P1的PC上运行的P2P服务器发送一个“库拉取”命令。此命令意味着库希望服务器从远程对等体拉取文件。P2P服务器从命令中获取远程对等体的端点,以及P1想要拉取的文件名和下载文件的文件夹,然后向远程对等体(P2)发送一个“对等体拉取”命令。P2的P2P服务器接受该命令,获取文件大小和CRC(CRC未实现),并将它们发送回P1。P1现在确切地知道要接受多少字节,并开始接收P2发送的位并将它们写入目标文件夹。在P2发送完所有字节且P1接收到它们之后,P1向P2发送一个“OK”响应(如果出现问题则发送“ERROR”)并关闭连接。这就是下载的大致过程。
防火墙后面的所有者
P1通过IFS Web服务为P2分配一个“推送任务”,并“认为”文件已经下载:) 某个时候,P2的P2P服务器通过IFSWS读取其任务,并看到它有一个“推送任务”。P2P向自身(任务读取器在另一个线程中)发出一个“库推送”命令。当对等体命令监听线程接收到该命令时,它获取文件大小和CRC(CRC再次未实现)并形成一个“对等体推送”命令。P2连接到P1(任务包含P1的端点)并发出“对等体推送”命令并开始流式传输文件。P1获取该命令,接收文件并将其存储在P2指示的目标文件夹中。(P2知道目标文件夹,因为P1已将其发送在“推送任务”中。)就是这样。
使用库
在您真正开始使用该库之前还有很长的路要走,但我们很快就会接触到这些内容(编译和配置IFS)。现在我只想向您展示使用IFSLIB是多么容易。
该库仅包含4个类,它们隐藏了所有关于点对点和Web服务的内容:`IfsSystem`、`IfsPeer`、`IfsFolder`和`IfsFile`。
为了使用IFS(在它已经设置好之后),您应该在存储库中注册为对等体。这再简单不过了,正如您稍后会看到的,但我首先要警告您:除非您已在IFS中注册或登录为对等体,否则您将无法使用IFS最重要的对象——`IfsSystem`对象。它被实现为单例,以避免在同一对等计算机上拥有多个IFS对等体实例。如果您实际上尝试使用`IfsSystem`类的最简单属性,您将收到一个运行时异常,指出您尚未登录/注册IFS。
首先,您必须注册为一个新的对等体
// first, you'll have to get a "handle" of the IFS singleton object
IfsSystem __gc* ifs = IfsSystem::Instance;
// now you can register
IfsPeer __gc* peer = ifs->RegisterPeer (
S"Stoyan Damov", // alias
S"Stoyan", // login name
S"Secret", // password
S"BG", // country code (unused in this version)
false); // behind firewall or NAT?
当然,您不能在IFS中注册多次(除非您准备好处理异常),所以一旦您注册成功,下次您应该登录
IfsPeer __gc* peer = ifs->LoginPeer (S"Stoyan", S"Secret");
// in fact you can throw the peer away, you won't use it for
// anything, except for examining its properties
一个对等体(`IfsPeer`实例)具有以下属性
- ID - IFS中唯一的对等体ID
- 别名 - 对等体可读的名称
- 登录 - 仅对对等体可见(其他对等体看到空字符串)
- 密码 - 同上
- IPEndPoint - 对等体的IP地址和端口
- BehindFirewall - 指示对等体是否在防火墙或NAT后面,即对等体的PC是否“可见”或外部“可连接”:)
一旦您注册或登录,就可以开始使用`IfsSystem`对象的属性,其中最重要(且可用)的是`RootFolder`属性,它返回一个`IfsFolder`对象,表示虚拟根文件夹。
使用文件夹
你可以如此轻松地获取根文件夹
IfsFolder __gc* root = ifs->RootFolder;
每个文件夹(包括根文件夹)都有几个属性
- ID - IFS中唯一的文件夹ID
- 名称
- 描述
- OwnerPeer - 文件夹所有者的IfsPeer对象
- ParentFolder - 父IfsFolder(按请求评估并缓存)
- PeerFolderPath - 所有者对等体PC上的物理文件夹
- VirtualPath - IFS逻辑路径(按请求评估并缓存)
- Published - 一个布尔标志,指示文件夹是否已发布,或者是一个全新的`IfsFolder`实例
到达根文件夹后,你可以用它做很多事情
- 在其中发布子文件夹
- 获取其所有子文件夹
- 查找具有指定名称的子文件夹(递归)
- 在其中发布文件
- 获取其所有文件
- 查找具有指定名称的文件(递归)
实际上,您可以对所有获取到指针的文件夹对象执行这些操作,并且可以非常轻松地获取任意文件夹,如下所示
IfsFolder __gc* folder = IfsFolder::GetFolderByPath (S"./Docs/PDF");
下面我将给出一些上述操作的示例,一旦您看到它们,就可以转到`IfsFolder`类的一些有用的静态方法。
您可以将一个文件夹发布到现有文件夹中
IfsFolder __gc* subFolder = root->PublishFolderHere (
S"VirtualFolderName",
S"Description", // may be omitted in an overload
S"c:\\physical\\folder\\path");
// and for more fun:
IfsFolder __gc* subSub = (root->PublishFolderHere (
S"Folder",
S"Description", // may be omitted in an overload
S"c:\\physical\\folder"))->PublishFolderHere (
S"SubFolder",
S"c:\\physical\\folder\\subFolder");
或者发布一个全新的文件夹
// when you know the destination path
IfsFolder __gc* folder = new IfsFolder (
S"VirtualName",
S"Description", // may be omitted in an overload
S"c:\\physical\\folder\\path");
folder->Publish ("./target/virtual/path");
// when you have the destination folder object
folder->Publish (targetFolder);
懒惰的人(包括我)可以使用静态方法发布文件夹
IfsFolder __gc* folder = IfsFolder::PublishFolder (
S"VirtualName",
S"Description", // may be omitted in an overload
S"c:\\physical\\folder\\path",
S"./target/virtual/path");
噢,我忘了告诉你如何重命名文件夹
// I assume you got one already
folder->RenameTo (S"NewFolderName"); // wow! how difficult :)
可能存在(也可能不存在)其他发布文件夹的方法(静态或实例方法),但我认为这些足以向您展示它是多么容易完成。现在,是时候看看您可以用已发布的文件夹做些什么了
您可以查找子文件夹
// the statement below will return all folders, arbitrary level
// below the "folder" one, which name is "docs" (recursively)
ArrayList __gc* folders = folder->FindSubFolders (S"docs");
或获取所有文件夹
// this statement will return all folders below the "folder" object
ArrayList __gc* folders = folder->GetFolders ();
甚至在整个IFS中查找文件夹
ArrayList __gc* folders = IfsFolder::FindFolders (S"docs");
// the above is equivalent to:
ArrayList __gc* folders = root->FindSubFolders (S"docs");
使用文件
在文章的上一版本中,我忘记写了很多关于文件的事情。我忘记告诉你一个文件(`IfsFile`)有一些有用的属性
- ID - IFS中唯一的文件ID
- 名称 - 文件的名称(不带路径)
- 描述 - 猜猜看:)
- OwnerPeer - 拥有文件的`IfsPeer`对象:)
- PeerFilePath - 所有者对等体PC上的完整路径(包括文件名)
- 文件夹 - 文件所在的`IfsFolder`对象
- Published - 一个布尔标志,指示文件是否已发布,或者是一个全新的`IfsFile`实例
再次,在之前的文章中,我提到`IfsFolder`有几个实例和静态方法来发布文件夹和文件。你知道为什么文件夹应该发布文件,而不是文件自己发布吗?因为我太蠢了。我无法在`IfsFile`类中使用`IfsFolder`类,因为那样会创建循环头文件包含。每个C++程序员都知道不应该包含头文件,而应该只在头文件中声明类,例如`class __gc* IfsFolder;`。我当时就是这么做的,但它不起作用,我以为要么我太烂,要么Visual C++太烂。好吧,我太烂了,但让我告诉你为什么。我忘记了IFS库中的所有类都包装在两个命名空间中。这就是为什么我应该在“IfsFile.h”头文件的命名空间中写入`class __gc* IfsFolder;`,或者将声明包装在命名空间中,像这样:`namespace InternetFileSystem { namespace Library { public __gc class IfsFolder; }}`。所以,我就是这么做的,现在`IfsFile`类有六个实例或静态发布方法。
你可以像这样创建一个全新的文件
IfsFile __gc* file = new IfsFile (
S"fileName",
S"file description", // may be omitted in an overload
S"x:\\full\\path\\to\\fileName");
并这样发布它
// a) calling the static Publish method (laziest)
IfsFile __gc* file = IfsFile::Publish (
S"fileName",
S"file description", // may be omitted in an overload
S"x:\\full\\path\\to\\fileName",
S"./ifs/target/path/");
// b) calling another static Publish method (you should have an
// IfsFolder before that) assuming you have the targetFolder,
// which is an instance of the IfsFolder class
IfsFile __gc* file = IfsFile::Publish (
S"fileName",
S"file description", // may be omitted in an overload
S"x:\\full\\path\\to\\fileName",
targetFolder);
// c) You have a brand new file and you want to publish it
file->Publish (S"./ifs/target/path/");
// d) You have a brand new file and an IfsFolder instance
// (targetFolder);
file->Publish (targetFolder);
您可以通过几种方式获取`IfsFile`对象
// get the file (assuming you have the folder already)
IfsFile __gc* file = folder->GetFile (S"readme.txt");
// get a folder's files
ArrayList __gc* files = folder->GetFiles ();
// or search in the whole IFS for a given file
ArrayList __gc* files = IfsFolder::FindFiles (S"readme.txt");
// now you get a file like this:
IfsFile __gc* file = static_cast<IfsFile __gc*> (files->get_Item (0));
典型的场景是从远程对等体下载文件
// this may not happen instantly
file->Download (S"c:\\local\\folder");<strike>
现在,文件的文件夹就是它的属性`Folder`。IfsFolder __gc* folder = file->Folder; // easier, I think :)
最后,猜猜文件是如何重命名的...我将把它留给你的想象力,但方法应该看起来像`RenameTo`:)。
`IfsFolder`和`IfsFile`类还有更多实例和静态方法,但您可以通过浏览源代码来查看和学习它们。
IFS浏览器
嗯,我尝试写一个大型的示例,说明如何使用这个库。它是一个(将是一个)功能齐全的类似Windows资源管理器的IFS浏览器,我称之为“IFS浏览器”:)。我时间不够了,所以没能完成它,但我实现了基本功能
- 注册对等体
- 登录对等体
- 地址栏,您可以在其中输入IFS URL,例如 ifs://pub/docs/
- 左侧的文件夹树 - 它可以工作,并按需展开文件夹
- 右侧的文件列表 - 它可以工作,并且可以重命名文件
- 向上一个文件夹工具栏按钮
- 菜单和工具栏按钮我认为值得拥有(其中大部分尚未工作)
- 有关更多信息,请参阅最新更改部分...
相信我,你可以在几个小时内实现所有其他功能!不过,我会在下周实现它们,所以如果你能等,你将免费获得一切。下面是IFS浏览器运行时的截图
编译和配置IFS
如果您拥有Visual Studio .NET的副本,那么您无需多做,只需编译解决方案文件即可。但是,如果您没有,请帮自己一个大忙,购买它,否则您将不得不等待一周,直到我完成本文的第2版并解释手动命令行编译。
编译
在VS .NET中打开解决方案文件并构建它。此步骤将在Bin文件夹中生成以下二进制文件
- IFSBrowser.exe - 类似Windows资源管理器的IFS浏览器
- InternetFileSystem.P2PServer.exe - 点对点服务器
- IFSWebService.dll - IFS Web服务代理
- InternetFileSystem.Library.dll - 您将使用的库
- InternetFileSystem.P2PFramework.dll - P2PSRV使用的框架
- InternetFileSystemWebService.dll - IFS Web服务
配置
除了更改下面解释的ConnectionString设置外,我不记得还有其他任何东西了。有一个配置文件,它将由P2P库自动创建(IFS库会将您的IP地址添加到其中),您可以在其中更改一些参数以适应您的需求
- 端口 - 这是P2P服务器将侦听的端口号(不要动它,除非您在所有地方都动它,并且网络中的每个对等体都这样做)
- P2PFmkNamespace - 这是P2P框架类所在的命名空间名称,服务器在收到请求时使用它来实例化适当的类型。如果您更改了点对点库的命名空间,则也应该更改此设置。
- ThreadSleepTime - 这是服务器工作线程每次循环等待请求时休眠的毫秒数
- ThreadJoinTime - 这是服务器停止的毫秒超时时间,直到线程被强制中止
设置IFS数据库
我选择Microsoft SQL Server作为IFS Web服务的后端,因为
IFS数据库非常简单,很难找到更简单的数据库。看看下面的图片,看看为什么
我想我在这里不应该解释什么,是吗?
现在,要设置数据库,您只需在您喜欢的工具(osql、isql、isqlw [查询分析器])中运行一个SQL脚本。该脚本的名称是InstallDatabase.sql,位于压缩源代码的Database文件夹中。它将创建一个名为“IFS”的数据库,以及其表和存储过程。注意:您需要编辑InstallDatabase.sql脚本并修改数据库的物理位置,因为我没有时间甚至编写一个简单的参数化批处理文件。就是这样。为了让IFSWS与数据库一起工作,您必须更改Web服务的web.config文件`<appSettings>`部分中的ConnectionString设置。我想您应该做的就是这些。要卸载数据库,请运行UninstallDatabase.sql脚本或手动删除数据库(这正是脚本所做的)。
关于MC++,一些技巧和陷阱
我为什么用Managed C++编写IFS?
微软一发布“C++托管扩展”规范和迁移指南,我就阅读并学习了它们。然而,我是一名全职开发人员,由于“不可能的任务”般的截止日期,我没有时间玩弄MC++,因为我还要学习很多其他东西(例如,准备2个MCSD .NET考试,学习HLA、MASM、ATL/WTL 7、ATL Server等),最后但同样重要的是,我必须关注(或者你称之为 :) 我的妻子。所以我只是想练习MC++,相信我,从C#(日常工作)切换到MC++(夜间乐趣)再反过来是非常不愉快的。IFS是我的第一个大于100行代码的MC++作品(实际上是大于5000行代码),我很感谢Chris Maunder设置了Web开发竞赛,帮助我练习MC++。
在我看来,如果你只使用.NET Framework和托管扩展(不带IJW和非托管代码),MC++并不比C#更强大。实际上,编写MC++代码更慢,而且在你最初的2,000行MC++代码中,你会经常忘记`__gc*`。此外,你会对微软对返回托管数组的函数的那种变态语法感到厌烦,比如:`unsigned char ReturnsManagedCharArray () __gc[];`。然而,VC++ .NET是编写托管或非托管应用程序的最佳选择,因为你实际上拥有两种语言和一整套SDK。
技巧和陷阱
嗯,我接下来要分享的这些想法,对于那些已经有.NET框架和MC++经验的人来说,并不是什么大技巧,但我知道有一些人会欣赏它们,而且我是在写这个段落之前写下这些的:) 您可能还想知道我在文本中隐藏了一个MC++编译器错误,所以请继续阅读...
- 自Beta 1以来一直在玩弄.NET,一年多后(现在),我发现自己又在重新发明轮子,这是程序员可能做的最糟糕的事情之一。因为我对网络类没有经验,我几乎重新实现了`NetworkStream`和另外几个类。这不好玩,当我看到文档中的它们时,我感到自己非常愚蠢。不要试图重新发明轮子。不要为自己找借口,说你没有时间阅读和学习所有东西(就像我一样:)。你必须这样做。相信我,它只会对你有好处。
- 不要使用`public`修饰符暴露`__gc`类的析构函数,否则你会在C# IDE中看到有趣的`dtor()`方法。然后,学习使用两个可见性修饰符(例如`private public`)来隐藏内部(程序集)方法不向公众公开。
- 不要忘记属性上的"get_"部分,也不要忘记前面的`__property`关键字:)。然后,记住`__property`想要放在`static`关键字之前。命运。
- 如果你用读取器/写入器封装你的流,让它们拥有这个流。这会让你免于关闭两者,因为关闭后者也会关闭底层的流。这也适用于NetworkStream,它会关闭底层的socket。
- 不要省略硬编码字符串上的“S”前缀,否则你会收到编译器的错误,这些错误倾向于指向正确的位置,但有时会显示奇怪的消息。此外,如果你有N个S"Hello"字符串,它们都将指向同一个`String __gc*`对象(我猜只有当你打开了字符串内联时)
- 在我看来,反射是.NET最酷的特性之一。学习并了解它们,因为它们有时会非常方便(参见Server类的HandleRequest方法,看看反射如何发挥作用,从而避免了本来不可避免的`switch`语句 [尽管switch比反射快])。
- 为此你可能会杀了我,但当其他技术会让你崩溃时,请使用`goto`。(想象一下你想要在一个try-catch-__finally块中检查N个条件,如果条件不满足,你想要退出try块,但在__finally块之后执行一些代码。你会怎么做?嵌套N个`if`?发明一个`break_block`关键字?:) 我甚至看到Jeff Richter使用`goto`来退出到try-catch块的末尾。
- 看在微软的份上,不要重命名你的Web服务文件。在IDE对话框中输入服务名称之前,请仔细考虑!我遇到了很多问题!
- 不要修改自动创建的与Web服务相关的VS.NET文件(.config、.asmx、.disco等)在其部署的文件夹中。在你的项目文件夹中修改它们——否则,VC++ .NET会检测到更改,并在下次重新编译WS时覆盖它们。
- 这是编译器 bug:使用 `static_cast` 解箱枚举。不要使用 `dynamic_cast` 或 `__try_cast`,否则编译器会崩溃。我以为我是第一个发现这个 bug 的人,但当我发布它之后,我才知道有人在一个月前就发现了 :)
我想分享一下关于警告的想法...
几个月前我做了一个梦(别笑),我发明了一种新的编程语言(好像现有的还不够一样),在梦中我给它命名为“p”。我猜它有类似C++的语法,但它非常奇怪,因为它没有do/while/for等控制语句。相反,它内置了适合世界上每种情况的算法(就像STL中的那些算法):)其中一个最酷的特性是“p”可以抛出异常和警告!事实上,我认为C#/VB/Java等高级语言应该拥有这样的特性。想象一下你有一个方法,它期望一些参数,检查它们,但决定以更有效的方式完成其工作,忽略你传递给它的参数。它可以抛出一个警告,你只有在感兴趣时才能捕获它,就像这样
void IntelligentMethod (int someHintValue)
{
int aBetterValue = CalulateBetterValue (someHintValue);
if (aBetterValue != someHintValue)
warn (new Warning (S"Ignoring someHintValue"));
// ...proceed with aBetterValue
}
是的,我知道用事件可以很容易地做到这一点,但它就是不一样,就像输入`op_Equality`与输入`==`不一样一样。而且说真的,我怀念HRESULT!我们没有严重性、设施等等。我们甚至没有一些代码。我知道我可以编写自己的派生自ApplicationException的异常,带有代码等,但不可避免的代码上的switch会很糟糕,并且会打破捕获正确(和预期异常)的想法,就像catch (MyException) { /* handle it */ }
catch (YourException) { /* ditto */ }
事实上,这可以通过以下方式实现// the base exceptions
public __gc class CriticalSeverityException : public Exception { ... };
public __gc class MediumSeverityException : public Exception { ... };
public __gc class LowSeverityException : public Exception { ... };
// the specific ones
public __gc class OutOfDiskSpaceException : public CriticalSeverityException { ... };
public __gc class AccessDeniedException : public CriticalSeverityException { ... };
public __gc class BusinessLogicException : public MediumSeverityException { ... };
// the one below is something like a warning...
public __gc class NearQuotaLimitException : public LowSeverityException { ... };
现在,我们可以用以下方式处理异常try
{
// do something, throwing exceptions
}
// this will catch both OutOfDiskSpace and AccessDenied exceptions
catch (CriticalSeverityException __gc* e) { /* whatever */ }
catch (BusinessLogicException __gc* e) { /* catch specific one */ }
// catches all LowSeverity exceptions
catch (LowSeverityException __gc* e) { /* ... */ }
__finally { /* ... */ }
我真的很想有一天看到像这样的结构(或不完全是这样)try
{
// do something wich throws exceptions and raises warnings
}
catch_warning (SpecificWarning __gc* w) { /* handle warning */ }
catch (Exception __gc*) { /* ... */ }
但够了。我一定是疯了 :) 如果你有什么想法,请与我分享,并请对这个发表评论。我真的很想知道是否还有其他人认为任何语言都需要警告。待办事项:哦,天哪!
我甚至不想开始这一部分,但我必须这样做。我想和你分享我原本想在IFS中添加的内容,但由于它是为比赛开发的,我没有时间。一旦我有空闲时间(这永远不会有),我将(最终)添加更多功能,但对于那些有兴趣改进它的爱好者,这是(很长)的列表
- 你在DB ERD中看不到它们,但它们存在!——表`Attributes`、`FileAttributes`和`FolderAttributes`。我原以为扩展`Files`和`Folders`表来存储大小、作者、上次访问时间等属性会非常愚蠢。所以我最初设计这些表是为了支持带有属性的文件和文件夹,但尚未在IFS Web服务中实现它们(尽管我在IFS库中实现了原型)。所以,总有一天实现它们会很酷(也许在我退休前的那一天:))。
- 用通配符("*","?")搜索文件夹和文件
- 同上,使用正则表达式(如在Linux中)
- 复制(下载)整个文件夹(+递归)——实际上这很简单,只需使用IFSLIB遍历并复制文件夹即可
- 上传/下载对等任务以处理“两个对等体都在防火墙后面”的情况
- 如果2个或更多的对等体注册了同一个文件,并且一个对等体请求它,IFSWS应该选择最近的对等体(可能基于CountryCode字段)——目前,“由多个对等体拥有的单个文件”和“选择最近的对等体”都没有实现。
- 编写一个功能齐全的IFS浏览器(GUI文件管理器)
- 用ANSI C/C++编写一个点对点服务器,这样Linux用户也能使用IFS
- 处理SOCKS代理、SSL连接等。
- 如此规模的虚拟文件系统不能没有某种负载均衡——然而,我既没有一堆电脑(嘿,我住在保加利亚:)),也没有时间将当前的IFS转换为一个超级可扩展的系统。
- 我至少还能想出20个功能...
结论
有力的写作是简洁的。一个句子不应包含不必要的词语,一个段落不应包含不必要的句子。[小威廉·斯特伦克]
因为我离一位精力充沛的作家还差得很远,感谢您阅读本文!这是我的第一篇文章,我发现我编写代码的速度是编写纯文本的10倍:)坦率地说,我羡慕那些著名作家——他们一定是很聪明的人!现在,关于这篇文章:我希望您看到了使用IFS库是多么容易。如果您仔细研究随本文提供的源代码,您会发现实现一个简单的互联网文件系统是多么容易。我是在一周内在两周内(现在已更新)在我的业余时间(即我的睡眠时间),而且我不是打字员,所以你甚至可以在更短的时间内完成。这就是.NET——一个适用于当今快节奏世界的RAD框架。错误会发生,即使在微软也会发生,但你不应该因此而停止学习和实践这项令人兴奋的新技术,在我看来,这项技术将在一年左右的时间内主宰开发世界(坦白告诉我,你见过哪项技术在不到6个月的时间里产生了超过150本书?我没有。)
报告错误
是的,它们确实存在。而且它们会咬人:) 截至本文撰写之时,IFS中没有bug(至少我不知道)。然而,有一个100%是微软的bug:它要么在ImageList中,要么在资源管理器中,要么在ToolBar类中。你将一些图像放入图像列表,将图像列表设置为工具栏,为工具栏按钮设置适当的图像索引,然后你期望它们显示出来,对吗?错了!它们要么根本不显示,要么其中一个会随处显示!这就是为什么我分发工具栏的图标,并用代码将它们放置在工具栏上。你应该将IFSBrowser\Resources\*.ico复制到Bin文件夹,否则IFS浏览器会崩溃。在文章的上一版中,我说存在第三个bug,与异常处理有关。我差不多修复了它,并且添加了一些有意义的IFS库抛出的异常:)
缺乏文档是一个大错误。我承诺会制作一份,但不幸的是,我现在工作压力很大,所以会在下一版本文章中生成.CHM帮助文件。抱歉!
将所有其他错误(和欢呼:)发送至 stoyan_damov@hotmail.com。我将非常乐意修复它们。但是,如果您修复了一个错误,请将其(以及修复)发送给我!谢谢!
最新更改
我希望你没有阅读过本文的上一版本。原因如下:
- 9月25日
- 耶!我成功运行了“推送任务”!远程对等体现在可以在防火墙/NAT后面。(顺便说一句,我低估了复杂性,浪费了几个小时追逐(不)存在的bug:)。
- 修复了P2P库中的2个bug(我很不好意思分享)
- IFS库现在检查空(0)参数并抛出`ArgumentNullException`
- 添加了几个存储过程,修复了一个
- 对IFS浏览器进行了一些工作:添加了文件和文件夹重命名功能,当您按下ENTER键时浏览器会导航(如预期),现在无论您如何到达任何文件夹,向上按钮都可正常工作(即,您可以键入“ifs://./folder/subfolder”,当您点击工具栏上的向上按钮时,浏览器将导航到父文件夹)。
- 9月24日
- 编辑了本文并添加了“最新更改”部分:)。
- 9月21日
- 修复了P2P库中的几个同步错误
- 使P2P库分块传输文件
- 9月19日
- 为`IfsFile`类添加了`Folder`属性
- 为`IfsFile`添加了`MoveTo`方法
- 为`IfsFile`添加了几个发布方法
- 重写了几个存储过程,编写了缺失的那些:)
- 修复了一些因无效对象状态导致的bug
- 为所有类添加了适当的访问修饰符
- 为IFS Web服务和P2P服务器添加了任务支持
- 9月16日至18日
- 修复了2个小错误
- 改进(重写)了`NetHelper`类
- 在所有(我记得的地方)都添加了(适当的?)异常处理:)
- 9月14日
- 初始版本(我希望你没有见过)
免责声明
本软件“按原样”提供,包含所有故障,不附带任何担保。请从任何开源许可证中选择最佳的免责声明,阅读并牢记。免费软件 = 无担保:) 然而,我授予您对源代码做任何事情的全部权利(除了为此起诉我:),我唯一想要的是您在心里感谢我:)