CASSINI源代码分析(3)

internal class Host : MarshalByRefObject {……}

首先,我们看到Host仅能够在cassini项目中使用,因为是 internal 的类定义。另外,继承自MarshalByRefObject,允许在支持远程处理的应用程序中跨应用程序域边界访问对象。我们联想到asp.net对于应用程序的执行方式是应用程序域为划分边界的,作为Host必须能够支持跨应用程序域,以便多个应用程序在其边界内执行。

先来看看其成员变量:

private bool _started;         //是否已经启动

        private bool _stopped;              //是否停止了

 

        private Server _server;              //对外交互父对象

 

        private int  _port;                    //以下大致应该是一个web server应当具有的内部变量

        private String _virtualPath;

        private String _lowerCasedVirtualPath;

        private String _lowerCasedVirtualPathWithTrailingSlash;

        private String _physicalPath;

        private String _installPath;

        private String _physicalClientScriptPath;

        private String _lowerCasedClientScriptPathWithTrailingSlashV10;

        private String _lowerCasedClientScriptPathWithTrailingSlashV11;

 

        private Socket _socket;                     //通信用的套接字

 

        private WaitCallback _onStart;        //回调函数

        private WaitCallback _onSocketAccept;    

        private EventHandler _onAppDomainUnload;          //事件监控,当某个应用程序域将要退出时候发生,由Host类处理。

public override Object InitializeLifetimeService() {

            return null; // never expire lease

        }是重载MarshalByRefObject的成员,正如源代码中的注释说言,通过返回null告诉.net framework永远不要将此类的实例失效过期。分布式垃圾回收负责控制服务器应用程序的生存期,并负责在它们的生存期到期时删除它们。传统上,分布式垃圾回收使用引用计数和 Ping 进行控制。这在每个对象有少数几个客户端时可以很好地工作,但在每个对象有数千个客户端时效率很低。生存期服务可采用传统分布式垃圾回收器的功能,并在客户端数目增加时能很好地扩展。

       Configure函数很值得分析,因为在Server.CreateHost中出现过,看看:

         public void Configure(Server server, int port, String virtualPath, String physicalPath, String installPath) {

            _server = server;

 

            _port = port;

            _virtualPath = virtualPath;

            _lowerCasedVirtualPath = CultureInfo.InvariantCulture.TextInfo.ToLower(_virtualPath);

            _lowerCasedVirtualPathWithTrailingSlash = virtualPath.EndsWith("/") ? virtualPath : virtualPath + "/";

            _lowerCasedVirtualPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(_lowerCasedVirtualPathWithTrailingSlash);

            _physicalPath = physicalPath;

_installPath = installPath;

//以上都是赋值和参数检验代码

            _physicalClientScriptPath = installPath + "\\asp.netclientfiles\\";

//以下开始确定asp.net提供的客户端脚本路径

            String version4 = FileVersionInfo.GetVersionInfo(typeof(HttpRuntime).Module.FullyQualifiedName).FileVersion;       //查找当前asp.net运行时模块的版本信息

            String version3 = version4.Substring(0, version4.LastIndexOf('.'));

            _lowerCasedClientScriptPathWithTrailingSlashV10 = "/aspnet_client/system_web/" + version4.Replace('.', '_') + "/";

            _lowerCasedClientScriptPathWithTrailingSlashV11 = "/aspnet_client/system_web/" + version3.Replace('.', '_') + "/";

 

                     //下面开始为套接字设置准备回调函数

            _onSocketAccept = new WaitCallback(OnSocketAccept);

            _onStart = new WaitCallback(OnStart);

 

            // start watching for app domain unloading

            _onAppDomainUnload = new EventHandler(OnAppDomainUnload);

            Thread.GetDomain().DomainUnload += _onAppDomainUnload;

        }

              显然,config函数做了以下事情:

1、  将一些配置参数传入到host类的内部变量

2、  确定asp.net提供的一些环境,譬如脚本环境、脚本存在的路径,以便asp.net的一些组件可以顺利执行(就象在IIS中一样)

3、  准备一些回调函数、事件监听函数处理发生的事件

外部使用host还通过Start过程,我们看看:

public void Start() {

            if (_started)         //已经启动了,不可启动两个实例

                throw new InvalidOperationException();

 

            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            _socket.Bind(new IPEndPoint(IPAddress.Any, _port));

            _socket.Listen((int)SocketOptionName.MaxConnections);

 

            _started = true;

            ThreadPool.QueueUserWorkItem(_onStart);

        }

该函数完成:

1、  排除启动两个实例

2、  在给定的端口上启动监听

3、  启动_onStart回调函数线程,运行监听套接字,但是是异步调用,start函数完成后马上返回。

_onStart函数是怎么处理的呢?

       private void OnStart(Object unused) {

            while (_started) {

                try {

                    Socket socket = _socket.Accept();

                    ThreadPool.QueueUserWorkItem(_onSocketAccept, socket);

                }

                catch {

                    Thread.Sleep(100);

                }

            }

 

            _stopped = true;

        }

              此线程一直进行循环,调用套接字的Accept函数,当一个连接接入到,马上调用一个新的线程(_onSocketAccept)和一个新的socket,然后产生一个新的线程来处理客户请求。遇到例外就暂停后继续Accept引入的套接字。一旦_started标志被设置false,则停止监听退出。

       private void OnSocketAccept(Object acceptedSocket) {

            Connection conn =  new Connection(this, (Socket)acceptedSocket);

            conn.ProcessOneRequest();

        }

此处线程马上产生一个Connection对象,并调用ConnectionProcessOneRequest来处理。看来真正处理一个web request的过程在Connection对象内。

posted @ 2004-11-28 01:49  QDuck  阅读(563)  评论(0编辑  收藏  举报