Remoting

合集下载

NET Remoting过时了吗为什么公司的项目还是选择用NET Remoting,而不是WCF

NET Remoting过时了吗为什么公司的项目还是选择用NET Remoting,而不是WCF

近两年看到很多介绍WCF分布式开发的文章,很少看到有深入介绍.NET Remoting开发的文章,似乎Remoting技术逐渐从大众的视野中消失了一样。

自从2005年发布这个名称为Indigo的技术以来,WCF逐渐成为.NET分布式开发的事实标准。

然后微软没有推崇和更新的技术,像我们这样的第三世界国家,唯微软马首是瞻,也纷纷转向WCF技术的实践与开发。

近期看到世界对SilverLight技术前展的担忧,就看到很明显的倾向。

一个以擅长开发平台(Platform,.NET)和开发工具(Visual Studio,SQL Sever)的公司,居然也能控制大量的中下游开发商的技术选择倾向,一想到最近在做的工作流WF的升级(.NET 3.0到.NET 4.0)的尴尬处境,令人叹息不已,这也许是IT产业链的特色。

我要提出的的观点是,作为通讯技术架构的.NET Remoting,并没有从我们的视野中消失,反而有很多产品还是继续使用和维护以.NET Remoting作为通讯架构方式。

我所看到的产品,是上市公司的产品,年收入是百万级别的产品,不用怀疑它是小企业的小应用。

所以,我要讨论一下,为什么.NET Remoting没有过时,更没有out。

先来看一下,要能成为企业应用的通讯架构技术基础,要满足的条件∙被传送的对象,消息(.NET Message)要容易定义,格式通用,灵活∙传递消息的方式,通常叫Channel, 灵活,支持各种应用环境,比如局域网选择TCP,互联网选择HTTP,进程间的通讯可选择Named Pipes或MSMQ。

∙被使用的服务(Services)要容易定义,并且可以灵活选择通道和消息格式抽象的说了这几点,不容易理解,来举例说明。

在ERP系统中,是如何做到简单灵活的应用通讯技术的。

以销售系统为例子,来看看它的架构方式。

消息格式定义销售单[Serializable]public partial class SalesOrderEntity : CommonEntityBase{public virtual System.String PriceCode{get { return (System.String)GetValue((int)SalesOrderFieldIndex.PriceCode, true); }set { SetValue((int)SalesOrderFieldIndex.PriceCode, value); }}public virtual System.String VendorNo{get { return (System.String)GetValue((int)SalesOrderFieldIndex.VendorNo, true); }set { SetValue((int)SalesOrderFieldIndex.VendorNo, value); }}}销售单只举例了两个属性,卖价编码和供应商商编码,在定义实体时,加Serializable特性表示可以序列化传递。

c# Remoting

c# Remoting

前言:在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来。

正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remoting的使用。

关于这个主题,在网上也有很多讨论,相关的技术文章也不少,遗憾的是,很多文章概述的都不太全面。

我在研究Remoting的时候,也对事件处理发生了兴趣。

经过参考相关的书籍、文档,并经过反复的试验,深信自己能够把这个问题阐述清楚了。

本文对于Remoting和事件的基础知识不再介绍,有兴趣的可以看我的系列文章,或查阅相关的技术文档。

本文示例代码下载:Remoting事件(客户端发传真)Remoting事件(服务端广播)Remoting事件(服务端广播改进)应用Remoting技术的分布式处理程序,通常包括三部分:远程对象、服务端、客户端。

因此从事件的方向上看,就应该有三种形式:1、服务端订阅客户端事件2、客户端订阅服务端事件3、客户端订阅客户端事件服务端订阅客户端事件,即由客户端发送消息,服务端捕捉该消息,然后响应该事件,相当于下级向上级发传真。

反过来,客户端订阅服务端事件,则是由服务端发送消息,此时,所有客户端均捕获该消息,激发事件,相当于是一个系统广播。

而客户端订阅客户端事件呢?就类似于聊天了。

由某个客户端发出消息,其他客户端捕获该消息,激发事件。

可惜的是,我并没有找到私聊的解决办法。

当客户端发出消息后,只要订阅了该事件的,都会获得该信息。

然而不管是哪一种方式,究其实质,真正包含事件的还是远程对象。

原理很简单,我们想一想,在Remoting中,客户端和服务端传递的内容是什么呢?毋庸置疑,是远程对象。

因此,我们传递的事件消息,自然是被远程对象所包裹。

这就像EMS快递,远程对象是运送信件的汽车,而事件消息就是汽车所装载的信件。

至于事件传递的方向,只是发送者和订阅者的角色发生了改变而已。

一、服务端订阅客户端事件服务端订阅客户端事件,相对比较简单。

rocketmq remoting 详解

rocketmq remoting 详解

rocketmq remoting 详解
RocketMQ是一款分布式消息中间件,具有高可靠性、高吞吐量、低延迟等特点。

remoting是RocketMQ中用于进行远程通信的核心模块,其设计和实现都具有一定的复杂性。

本文将详细介绍RocketMQ remoting的设计思路、实现原理以及常见问题解决方案,帮助读者深入理解RocketMQ的核心技术,提升自身技术水平。

文章主要分为以下几个部分:
1. remoting概述:介绍remoting的作用和功能,以及与其他通信框架的比较。

2. remoting设计思路:介绍remoting的设计目标和思路,包括如何实现高可靠性、高性能以及可扩展性等方面。

3. remoting实现原理:详细介绍remoting的实现原理,包括网络通信、序列化、心跳检测、断线重连等方面。

4. remoting常见问题解决方案:介绍常见的问题及其解决方案,包括网络连接超时、连接异常、序列化异常、心跳超时等问题。

通过本文的介绍,读者可以全面了解RocketMQ remoting的实现原理和使用方法,提高自身技术水平,为项目的开发和运维提供有力支持。

- 1 -。

Remoting基本原理及其扩展机制下

Remoting基本原理及其扩展机制下

Remoting基本原理及其扩展机制(下)让我们在开始本节内容之前先了解以下几个基本概念。

应用程序域应用程序域(通常简称为AppDomain)可以视为一种轻量级进程。

一个Windows进程内可以包含多个AppDomain。

AppDomain这个概念的提出是为了实现在一个物理服务器中承载多个应用程序,并且这些应用能够相互独立。

中利用AppDomain在同一个进程内承载了多组Web应用程序就是一个例子。

实际上微软曾进行过在单一进程内承载多达1000个简单Web应用程序的压力测试。

使用AppDomain所获得的性能优势主要体现在两方面:∙创建AppDomain所需要的系统资源比创建一个Windows进程更少。

∙同一个Windows进程内所承载的AppDomain之间可以互相共享资源,如CLR、基本.NET类型、地址空间以及线程。

而各个AppDomain之间的独立性体现为以下这些特征:∙一个AppDomain可以独立于其他的AppDomain而被卸载。

∙一个AppDomain无法访问其他AppDomain的程序集和对象。

∙若没有发生跨边界的异常抛出,一个AppDomain拥有自己独立的异常管理策略。

这意味着一个AppDomain内出现问题不会影响到同一个进程内中的其他AppDomain。

∙每个AppDomain可以分别定义独自的程序集代码访问安全策略。

∙每个AppDomain可以分别定义独自的规则以便CLR在加载前定位程序集所在位置。

可以看出应用程序域是进程中的一个子单元,不过在.NET中还存在一个比应用程序域还要细粒度的单元——.NET上下文(Context)。

.NET Context一个.NET 应用程序域能够包含多个被称为.NET上下文的实体。

所有.NET对象都存在于上下文中,每个应用程序域中至少存在一个上下文。

这个上下文称为应用程序域的默认上下文,它在应用程序域创建的时候就创建了。

下图总结了它们之间的关系:那么MessageSink与上下文有什么关系呢?我们知道在通常情况下,如果访问同一个AppDomain中对象的方法时,会采用基于栈的方式(详见本系列上部)。

.Net Remoting(基本操作) - Part.2

.Net Remoting(基本操作) - Part.2

// 注册 tcp 通道 ChannelServices.RegisterChannel(tcpChnl, false);
// 注册 http 通道 IChannel httpChnl = new HttpChannel(8502); ChannelServices.RegisterChannel(httpChnl, false); } } }
1.客户端(客户应用程序)
客户端的处理包含三个基本的组成部分,代理(Proxy)、格式器(Formatter) 和 通道(Channel)。 客户端总是通过一个代理来和服务端对象进行交互。客户端向代理请求属性或者方法调用,然后代理将请求发送给服务端的对象。每一个代 理绑定一个远程对象,多个代理也可以绑定同一个对象(Singleton 方式,后面会介绍);客户端的多个对象也可以使用同一个代理。代理分为两 部分,一个名为透明代理(Transparent Proxy),一个名为真实代理(Real Proxy)。透明代理提供了和服务对象完全一致的公共接口,当客户进行 方法调用时,透明代理将栈帧(Stack Frame,在栈中为参数、返回地址和局部变量保留的一块内存区,必要时在过程调用中使用)转换为消息 (Message),然后将消息发送给真实代理。这个消息对象包含了调用的对象的方法信息,包括方法签名、参数等,同时还包括客户端的位置(注意 这里,方法回调(Callback)时会再提到)。真实代理知道如何连接远程对象并将消息发送给它。 真实代理收到消息后,请求 Formatter 对象对其进行序列化,同时将客户程序中断(block)。.Net 内置了两种序列化格式,一种是二进制 Binary,一种是 SOAP。Formatter 将消息进行序列化之后,然后将其发送到通道中,由通道将消息发送到远程对象。当请求返回时,Formatter 将返回的消息反序列化,然后再提交给代理,代理将返回值放到发送请求的客户对象的调用堆栈上,随后将控制返回给客户调用程序(解除中断)。 这样就给了客户对象一个错觉:代理即为远程对象。

三层架构的思想

三层架构的思想

三层架构的思想关于三层架构(3-tier application) 通常意义上的三层架构就是将整个业务应⽤划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。

区分层次的⽬的即为了“⾼内聚,低耦合”的思想。

1、表现层(UI):通俗讲就是展现给⽤户的界⾯,即⽤户在使⽤⼀个系统的时候他的所见所得。

2、业务逻辑层(BLL):针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。

3、数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增、删、改、查。

概述在软件体系架构设计中,分层式结构是最常见,也是最重要的⼀种结构。

微软推荐的分层式结构⼀般分为三层,从下⾄上分别为:数据访问层、业务逻辑层(⼜或成为领域层)、表⽰层。

三层结构原理:3个层次中,系统主要功能和业务逻辑都在业务逻辑层进⾏处理。

所谓三层体系结构,是在客户端与数据库之间加⼊了⼀个“中间层”,也叫层。

这⾥所说的三层体系,不是指物理上的三层,不是简单地放置三台机器就是三层体系结构,也不仅仅有B/S应⽤才是三层体系结构,三层是指逻辑上的三层,即使这三个层放置到⼀台机器上。

三层体系的应⽤程序将业务规则、数据访问、合法性校验等⼯作放到了中间层进⾏处理。

通常情况下,客户端不直接与数据库进⾏交互,⽽是通过COM/DCOM通讯与中间层建⽴连接,再经由中间层与数据库进⾏交互。

表⽰层位于最外层(最上层),离⽤户最近。

⽤于显⽰数据和接收⽤户输⼊的数据,为⽤户提供⼀种交互式操作的界⾯。

业务逻辑层业务逻辑层(Business Logic Layer)⽆疑是架构中体现核⼼价值的部分。

它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计,也即是说它是与系统所应对的领域(Domain)逻辑有关,很多时候,也将业务逻辑层称为领域层。

例如Martin Fowler在《Patterns of Enterprise Application Architecture》⼀书中,将整个架构分为三个主要的层:表⽰层、领域层和数据源层。

remoting 通信原理

remoting 通信原理

remoting 通信原理Remoting通信原理Remoting是一种用于实现分布式系统通信的技术,它允许不同的应用程序在不同的进程或机器之间进行通信。

本文将介绍Remoting通信的原理和工作机制。

一、什么是Remoting通信Remoting是一种远程过程调用(RPC)的实现方式,它允许应用程序通过网络在不同的主机上调用远程对象的方法。

通过Remoting,应用程序可以像调用本地对象一样调用远程对象,无需关心网络通信的细节。

二、Remoting通信原理Remoting通信的原理可以分为以下几个步骤:1. 客户端代理创建客户端需要创建一个代理对象来代表远程对象。

客户端代理对象与远程对象具有相同的接口,客户端通过调用代理对象的方法来实现与远程对象的通信。

2. 序列化当客户端调用代理对象的方法时,参数和返回值需要进行序列化,即将对象转换为字节流以便在网络上传输。

序列化是将对象的状态转换为字节序列的过程,可以通过Java的序列化机制或其他序列化方式来实现。

3. 通信传输序列化后的数据将通过网络传输到远程主机。

在传输过程中,需要使用网络协议将数据分割为小的数据包,并通过网络传输协议(如TCP/IP)进行传输。

4. 服务器端接收远程主机接收到数据后,需要将数据反序列化为对象。

服务器端需要根据接收到的数据,找到对应的远程对象,并调用相应的方法。

5. 远程方法调用服务器端接收到数据并反序列化后,将调用远程对象的方法。

服务器端执行方法后,将返回值进行序列化,并通过网络传输到客户端。

6. 客户端接收客户端接收到服务器端返回的数据后,需要将数据反序列化为对象,并将结果返回给调用方。

三、Remoting通信的优势Remoting通信具有以下几个优势:1. 透明性通过Remoting,客户端可以像调用本地对象一样调用远程对象的方法,无需关心网络通信的细节。

这种透明性使得分布式系统的开发更加简单。

2. 性能Remoting通信采用了二进制序列化的方式,相比其他文本序列化方式具有更高的性能。

WAS中间件服务器介绍

WAS中间件服务器介绍

Web application server 网络应用服务器-----WASClient (客户端)Server (服务器)Business logic server (业务逻辑服务器)DBMS Server (数据库服务器)Business Object Server (业务对象服务器)Navigator (一个浏览器)Microsoft IE (微软的一个浏览器IE)Web Client (网络客户端)Apache (是世界排名第一的WEB服务器软件)Microsoft IIS (Internet Information Services 互联网信息服务)微软件互联网信息服务亦是一种WEB服务器,可参考“微软件的IIS会对APACHE构成胁吗?”一文。

Application Server(应用服务器)HTTP(Hypertext transfer protocol)超文本转移协议(HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

Servlet是在服务器上运行的小程序。

它通常用于在客户端运行,结果得到为用户进行运算或者根据用户互作用定位图形等服务。

常常是根据用户输入访问数据库的程序。

这些通常是使用公共网关接口(CGI(Common Gateway Interface))应用程序完成的。

JSP(Java Server Pages) 是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。

Servlet与JSP的区别可参见“Servlet与JSP的区别”一文。

是一项微软公司的技术,是一种使嵌入网页中的脚本可由因特网服务器执行的服务器端脚本技术。

RMI(Remote Method Invocation,远程方法调用),可参见“远程调用的几种方式”一文。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、Remoting基础什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式。

从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下。

Mic rosoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。

这也正是我们使用Remoting的原因。

为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。

这个进程形成了应用程序代码和数据周围的一道边界。

如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。

这是一种操作系统对应用程序的保护机制。

然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。

在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。

如图所示:首先,客户端通过Remoting,访问通道以获得服务端对象,再通过代理解析为客户端对象。

这就提供一种可能性,即以服务的方式来发布服务器对象。

远程对象代码可以运行在服务器上(如服务器激活的对象和客户端激活的对象),然后客户端再通过Remoting连接服务器,获得该服务对象并通过序列化在客户端运行。

在Remoting中,对于要传递的对象,设计者除了需要了解通道的类型和端口号之外,无需再了解数据包的格式。

但必须注意的是,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。

这既保证了客户端和服务器端有关对象的松散耦合,同时也优化了通信的性能。

1、Remoting的两种通道Remoting的通道主要有两种:Tcp和Http。

在.Net中,System.Runtime.Remoting.Channel中定义了IChannel接口。

IChannel接口包括了TcpChannel通道类型和Http通道类型。

它们分别对应Rem oting通道的这两种类型。

TcpChannel类型放在名字空间System.Runtime.Remoting.Channel.Tcp中。

Tcp通道提供了基于Soc ket的传输工具,使用Tcp协议来跨越Remoting边界传输序列化的消息流。

TcpChannel类型默认使用二进制格式序列化消息对象,因此它具有更高的传输性能。

HttpChannel类型放在名字空间Syste m.Runtime.Remoting.Channel.Http中。

它提供了一种使用Http协议,使其能在Internet上穿越防火墙传输序列化消息流。

默认情况下,HttpChannel类型使用Soap格式序列化消息对象,因此它具有更好的互操作性。

通常在局域网内,我们更多地使用TcpChannel;如果要穿越防火墙,则使用Ht tpChannel。

2、远程对象的激活方式在访问远程类型的一个对象实例之前,必须通过一个名为Activation的进程创建它并进行初始化。

这种客户端通过通道来创建远程对象,称为对象的激活。

在Remoting中,远程对象的激活分为两大类:服务器端激活和客户端激活。

(1) 服务器端激活,又叫做WellKnow方式,很多又翻译为知名对象。

为什么称为知名对象激活模式呢?是因为服务器应用程序在激活对象实例之前会在一个众所周知的统一资源标识符(URI)上来发布这个类型。

然后该服务器进程会为此类型配置一个WellKnown对象,并根据指定的端口或地址来发布对象。

.Net Remoting把服务器端激活又分为SingleTon模式和SingleCall模式两种。

SingleTon模式:此为有状态模式。

如果设置为SingleTon激活方式,则Remoting将为所有客户端建立同一个对象实例。

当对象处于活动状态时,SingleTon实例会处理所有后来的客户端访问请求,而不管它们是同一个客户端,还是其他客户端。

SingleTon实例将在方法调用中一直维持其状态。

举例来说,如果一个远程对象有一个累加方法(i=0;++i),被多个客户端(例如两个)调用。

如果设置为SingleTon方式,则第一个客户获得值为1,第二个客户获得值为2,因为他们获得的对象实例是相同的。

如果熟悉的状态管理,我们可以认为它是一种Application状态。

SingleCall模式:SingleCall是一种无状态模式。

一旦设置为SingleCall模式,则当客户端调用远程对象的方法时,Remoting会为每一个客户端建立一个远程对象实例,至于对象实例的销毁则是由GC自动管理的。

同上一个例子而言,则访问远程对象的两个客户获得的都是1。

我们仍然可以借鉴的状态管理,认为它是一种Session状态。

(2) 客户端激活。

与WellKnown模式不同,Remoting在激活每个对象实例的时候,会给每个客户端激活的类型指派一个URI。

客户端激活模式一旦获得客户端的请求,将为每一个客户端都建立一个实例引用。

SingleCall模式和客户端激活模式是有区别的:首先,对象实例创建的时间不一样。

客户端激活方式是客户一旦发出调用的请求,就实例化;而SingleCall则是要等到调用对象方法时再创建。

其次,SingleCall模式激活的对象是无状态的,对象生命期的管理是由GC管理的,而客户端激活的对象则有状态,其生命周期可自定义。

其三,两种激活模式在服务器端和客户端实现的方法不一样。

尤其是在客户端,SingleCall模式是由GetObject()来激活,它调用对象默认的构造函数。

而客户端激活模式,则通过CreateInstance()来激活,它可以传递参数,所以可以调用自定义的构造函数来创建实例。

二、远程对象的定义前面讲到,客户端在获取服务器端对象时,并不是获得实际的服务端对象,而是获得它的引用。

因此在Remoting中,对于远程对象有一些必须的定义规范要遵循。

由于Remoting传递的对象是以引用的方式,因此所传递的远程对象类必须继承MarshalByRefObjec t。

MSDN对MarshalByRefObject的说明是:MarshalByRefObject 是那些通过使用代理交换消息来跨越应用程序域边界进行通信的对象的基类。

不是从 MarshalByRefObject 继承的对象会以隐式方式按值封送。

当远程应用程序引用一个按值封送的对象时,将跨越远程处理边界传递该对象的副本。

因为您希望使用代理方法而不是副本方法进行通信,因此需要继承MarshallByRefObject。

以下是一个远程对象类的定义:public class ServerObject:MarshalByRefObject{public Person GetPersonInfo(string name,string sex,int age){Person person = new Person(); = name;person.Sex = sex;person.Age = age;return person;}}这个类只实现了最简单的方法,就是设置一个人的基本信息,并返回一个Person类对象。

注意这里返回的Person类。

由于这里所传递的Person则是以传值的方式来完成的,而Remoting要求必须是引用的对象,所以必须将Person类序列化。

因此,在Remoting中的远程对象中,如果还要调用或传递某个对象,例如类,或者结构,则该类或结构则必须实现串行化Attribute[SerializableAttribute]:[Serializable]public class Person{public Person(){}private string name;private string sex;private int age;public string Name{get {return name;}set {name = value;}}public string Sex{get {return sex;}set {sex = value;}}public int Age{get {return age;}set {age = value;}}}将该远程对象以类库的方式编译成Dll。

这个Dll将分别放在服务器端和客户端,以添加引用。

在Remoting中能够传递的远程对象可以是各种类型,包括复杂的DataSet对象,只要它能够被序列化。

远程对象也可以包含事件,但服务器端对于事件的处理比较特殊,我将在本系列之三中介绍。

三、服务器端根据第一部分所述,根据激活模式的不同,通道类型的不同服务器端的实现方式也有所不同。

大体上说,服务器端应分为三步:1、注册通道要跨越应用程序域进行通信,必须实现通道。

如前所述,Remoting提供了IChannel接口,分别包含TcpChannel和HttpChannel两种类型的通道。

这两种类型除了性能和序列化数据的格式不同外,实现的方式完全一致,因此下面我们就以TcpChannel为例。

注册TcpChannel,首先要在项目中添加引用“System.Runtime.Remoting”,然后using名字空间:System.Runtime.Remoting.Channel.Tcp。

代码如下:TcpChannel channel = new TcpChannel(8080);ChannelServices.RegisterChannel(channel);在实例化通道对象时,将端口号作为参数传递。

然后再调用静态方法RegisterChannel()来注册该通道对象即可。

2、注册远程对象注册了通道后,要能激活远程对象,必须在通道中注册该对象。

根据激活模式的不同,注册对象的方法也不同。

(1) SingleTon模式(服务端激活)对于WellKnown对象,可以通过静态方法RemotingConfiguration.RegisterWellKnownServiceType (typeof(ServerRemoteObject.ServerObject),"ServiceMessage",WellKnownObjectMode.SingleTon)来实现:(2)SingleCall模式(服务端激活)注册对象的方法基本上和SingleTon模式相同,只需要将枚举参数WellKnownObjectMode改为Singl eCall就可以了。

RemotingConfiguration.RegisterWellKnownServiceType(typeof(ServerRemoteObject.Se rverObject),"ServiceMessage",WellKnownObjectMode.SingleCall);(3)客户端激活模式对于客户端激活模式,使用的方法又有不同,但区别不大,看了代码就一目了然。

相关文档
最新文档