65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (36投票s)

2002年9月20日

27分钟阅读

viewsIcon

356198

downloadIcon

4438

从头开始构建 Internet 文件系统 - 使 Web 服务和 P2P 技术协同工作以构建虚拟文件系统

本页内容

  1. 引言
  2. 什么是互联网文件系统?
    1. IFS架构
    2. 为什么这个IFS很(或将)酷?
    3. 它是如何工作的?
  3. 使用库
    1. 对等体注册与登录
    2. 使用文件夹
    3. 使用文件
  4. IFS浏览器
  5. 编译和配置IFS
    1. 编译
    2. 配置
    3. 设置IFS数据库
  6. 关于MC++,一些技巧和陷阱
  7. 我想分享的关于警告的想法...
  8. 待办事项:哦,天哪!
  9. 结论
  10. 报告错误
  11. 最新更改
  12. 免责声明

简介

你可能见过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 Architecture Diagram

如上图所示,这里有两个主要部分: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

  • 两个对等体都不在防火墙后面
  • 没问题。P1P2拉取文件

  • P2在防火墙后面
  • 哎呀!P1无法轻易连接到P2。那么它能做什么呢?它可以执行一个Web服务方法,该方法将分配一个任务给P2,让P2将文件推送到P1P2的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 Browser Screenshot

编译和配置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 - 这是服务器停止的毫秒超时时间,直到线程被强制中止
配置文件将在通用应用程序文件夹中创建,即在Windows 2K及更高版本上为 X:\Documents and Settings\All Users\Application Data\。

设置IFS数据库

我选择Microsoft SQL Server作为IFS Web服务的后端,因为

  • 我爱微软 :)
  • 我使用MS SQL Server的经验比使用任何其他数据库都多,尽管XML或纯文本文件也足以运行IFS(但您必须更改很多Web服务代码)
  • IFS数据库非常简单,很难找到更简单的数据库。看看下面的图片,看看为什么

      IFS Database ERD Diagram  

    我想我在这里不应该解释什么,是吗?

    现在,要设置数据库,您只需在您喜欢的工具(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日
    • 初始版本(我希望你没有见过)

    免责声明

    本软件“按原样”提供,包含所有故障,不附带任何担保。请从任何开源许可证中选择最佳的免责声明,阅读并牢记。免费软件 = 无担保:) 然而,我授予您对源代码做任何事情的全部权利(除了为此起诉我:),我唯一想要的是您在心里感谢我:)

    © . All rights reserved.