SharedCache分析:服务端程序
2008-02-07 23:10 无常 阅读(3797) 评论(4) 收藏 举报SharedCache由3个主要的项目组成MergeSystem.Indexus.WinServiceCommon、MergeSystem.Indexus.WinService和MergeSystem.Indexus.Notify。WinService可以以Windows服务方式加载,也可以以控制台方式运行,如果注册为Windows服务,则可以通过MergeSystem.Indexus.Notify程序来了解其状态,若是以控制台方式运行,则运行时的信息会在控制台窗口中显示。当然也可以配置通过NLog.dll记录日志。
大部分的功能都封装在WinServiceCommon项目中,WinService项目只负责监听和数据中转,这个项目中只有几个文件,如图1。
Indexus是个windows服务,也是程序的入口点,其类图如图2。
| 图1 | 图2 | 
| 图3 ShareCache服务端程序主流程 | 
Indexus可以接受几个命令行参数/install /i /uninstall /u来安装或卸载windows服务,若想以控制台方式启动程序,可以使用/local参数,如:
MergeSystem.Indexus.WinService.exe /local
或直接使用相同目录中的几个批处理文件来执行。来看一下main函数:
 public static void Main(string[] args)
public static void Main(string[] args) {
{ Access Log Access Log
    Access Log Access Log 
 string optionalArgs = string.Empty;
    string optionalArgs = string.Empty; if (args.Length > 0)
    if (args.Length > 0) {
    { optionalArgs = args[0];
        optionalArgs = args[0]; }
    } args Handling args Handling
    args Handling args Handling }
}

这里可以看到,加/local参数启动时,直接调用StartService()方法,然后就是和安装windows服务后启动服务一样了。
StartService中调用ServiceLogic.Init()方法进行初始化。代码注释比较少,但已经够我们理解这段代码了。
 /// <summary>
/// <summary> /// Inits this instance. This method used at startup to initialize
/// Inits this instance. This method used at startup to initialize  /// all required server components
/// all required server components /// </summary>
/// </summary> public void Init()
public void Init() {
{ Access Log Access Log
    Access Log Access Log 
 COM.Handler.LogHandler.Force("Initializing Settings" + COM.Enums.LogCategory.ServiceStart.ToString());
    COM.Handler.LogHandler.Force("Initializing Settings" + COM.Enums.LogCategory.ServiceStart.ToString()); Console.WriteLine(@"Welcome to indeXus.Net Shared Cache");
    Console.WriteLine(@"Welcome to indeXus.Net Shared Cache"); Console.WriteLine();
    Console.WriteLine(); Console.WriteLine(COM.Handler.Config.DisplayAppSettings());
    Console.WriteLine(COM.Handler.Config.DisplayAppSettings()); COM.Handler.LogHandler.Info(COM.Handler.Config.DisplayAppSettings());
    COM.Handler.LogHandler.Info(COM.Handler.Config.DisplayAppSettings()); // needs to be instantiated before TCP, it needs an instance of CachExpire
    // needs to be instantiated before TCP, it needs an instance of CachExpire cacheExpireInstance = new CacheExpire();
    cacheExpireInstance = new CacheExpire(); // TCP needs an instance of CacheExpire
    // TCP needs an instance of CacheExpire tcpInstance = new TcpServer(cacheExpireInstance);
    tcpInstance = new TcpServer(cacheExpireInstance); 
 COM.Handler.LogHandler.Force("Init and Start Thread Tcp");
    COM.Handler.LogHandler.Force("Init and Start Thread Tcp"); COM.Handler.LogHandler.Force("Init and Start Thread CacheExpire");
    COM.Handler.LogHandler.Force("Init and Start Thread CacheExpire"); // Init all extenders
    // Init all extenders // an extender is a class which initializes its own logic around
    // an extender is a class which initializes its own logic around  // specific issue within its own thread;
    // specific issue within its own thread; ///////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////// this.workerTcp = new Thread(this.tcpInstance.Init);
    this.workerTcp = new Thread(this.tcpInstance.Init); this.workerTcp.Name = "TCP Handler";
    this.workerTcp.Name = "TCP Handler"; this.workerTcp.IsBackground = true;
    this.workerTcp.IsBackground = true; this.workerTcp.Priority = ThreadPriority.Normal;
    this.workerTcp.Priority = ThreadPriority.Normal; ///////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////// this.workerCacheExpire = new Thread(this.cacheExpireInstance.Init);
    this.workerCacheExpire = new Thread(this.cacheExpireInstance.Init); this.workerCacheExpire.Name = "Cache Expire Handler";
    this.workerCacheExpire.Name = "Cache Expire Handler"; this.workerCacheExpire.IsBackground = true;
    this.workerCacheExpire.IsBackground = true; this.workerCacheExpire.Priority = ThreadPriority.Lowest;
    this.workerCacheExpire.Priority = ThreadPriority.Lowest; ///////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////// this.workerCacheExpire.Start();
    this.workerCacheExpire.Start(); this.workerTcp.Start();
    this.workerTcp.Start(); 
 // enable the search of replicaiton servers
    // enable the search of replicaiton servers if (this.enableServiceFamilyMode)
    if (this.enableServiceFamilyMode) {
    { NetworkDistribution.Init();
        NetworkDistribution.Init(); }
    } 
 string msgThreadInfo = Environment.NewLine +
    string msgThreadInfo = Environment.NewLine +  "Main Thread Id: " + Thread.CurrentThread.ManagedThreadId.ToString() + Environment.NewLine +
        "Main Thread Id: " + Thread.CurrentThread.ManagedThreadId.ToString() + Environment.NewLine + "this.workerTcp: " + this.workerTcp.ManagedThreadId.ToString() + Environment.NewLine +
        "this.workerTcp: " + this.workerTcp.ManagedThreadId.ToString() + Environment.NewLine + /*"this.workerTimer: " + this.workerTimer.ManagedThreadId.ToString() + Environment.NewLine +*/
        /*"this.workerTimer: " + this.workerTimer.ManagedThreadId.ToString() + Environment.NewLine +*/ "this.workerCacheExpire: " + this.workerCacheExpire.ManagedThreadId.ToString();
        "this.workerCacheExpire: " + this.workerCacheExpire.ManagedThreadId.ToString(); 
 Console.WriteLine(msgThreadInfo + Environment.NewLine);
    Console.WriteLine(msgThreadInfo + Environment.NewLine); Console.WriteLine("+ + + + + + + + + + + + + + + + + + + + + + + + + + + + ");
    Console.WriteLine("+ + + + + + + + + + + + + + + + + + + + + + + + + + + + "); Console.WriteLine("server is ready to receive data.");
    Console.WriteLine("server is ready to receive data."); 
 COM.Handler.LogHandler.Force("IndeXus.Net Service Started " + COM.Enums.LogCategory.ServiceStart.ToString());
    COM.Handler.LogHandler.Force("IndeXus.Net Service Started " + COM.Enums.LogCategory.ServiceStart.ToString()); }
}
这里启动2个Thread,一个负责执行CacheExpire.Init()方法,负责定时轮查缓Cache中设置有过期策略的对象,如果有到期的,就从Cache中清除。另一个Thread负责监听TCP端口,然后每有一个新的客户端连接过来,又启动一个新的线程处理。
接下来转到MergeSystem.Indexus.WinService.TcpServer.Init()方法:
 public void Init()
public void Init() {
{ 
    

 IPEndPoint endpoint = COM.Handler.Network.GetServerAnyIPEndPoint(this.cacheIpPort);
    IPEndPoint endpoint = COM.Handler.Network.GetServerAnyIPEndPoint(this.cacheIpPort); 
 serverSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    serverSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(endpoint);
    serverSocket.Bind(endpoint); serverSocket.Listen((int)SocketOptionName.MaxConnections);
    serverSocket.Listen((int)SocketOptionName.MaxConnections); 
 
    

 // setup listener issues
    // setup listener issues acceptThread = new Thread(AcceptConnections);
    acceptThread = new Thread(AcceptConnections); acceptThread.IsBackground = true;
    acceptThread.IsBackground = true; acceptThread.Priority = ThreadPriority.Normal;
    acceptThread.Priority = ThreadPriority.Normal; acceptThread.Start();
    acceptThread.Start(); 
 
    

 }
}

这里启动一个新线程监听TCP 48888(默认值)端口,跟到AcceptConnections方法:
 private void AcceptConnections()
private void AcceptConnections() {
{ 
    

 while (true)
    while (true) {
    { // Accept a connection
        // Accept a connection Socket socket = serverSocket.Accept();
        Socket socket = serverSocket.Accept(); ConnectionInfo connection = new ConnectionInfo();
        ConnectionInfo connection = new ConnectionInfo(); connection.Socket = socket;
        connection.Socket = socket; 
 // Modified:06-01-2008 Merge System GmbH, rschuetz : for more information checkout the following link> http://netrsc.blogspot.com/2007/02/another-extract-from-scalenet-threading.html
        // Modified:06-01-2008 Merge System GmbH, rschuetz : for more information checkout the following link> http://netrsc.blogspot.com/2007/02/another-extract-from-scalenet-threading.html ThreadPool.QueueUserWorkItem(this.ProcessConnection, connection);
        ThreadPool.QueueUserWorkItem(this.ProcessConnection, connection); 
 // Store the socket in the open connections
        // Store the socket in the open connections lock (this.connections)
        lock (this.connections) {
        { this.connections.Add(connection);
            this.connections.Add(connection); }
        } 
 }
    } }
}

这个比较简单,只是在一个死循环中等待客户端连接,等到后要线程池中执行ProcessConnection方法来处理,此线程继续等待下一个请求。跟到ProcessConnection方法:
 private void ProcessConnection(object stats)
private void ProcessConnection(object stats) {
{ 
     
 
 ConnectionInfo connection = (ConnectionInfo)stats;
    ConnectionInfo connection = (ConnectionInfo)stats; 
 try
    try {
    { 
        

 // read data from Socket and convert it to an IndeXusMessage
        // read data from Socket and convert it to an IndeXusMessage COM.IndexusMessage msg = new COM.Handler.NetworkMessage().ProcessNetworkMessage(connection.Socket);
        COM.IndexusMessage msg = new COM.Handler.NetworkMessage().ProcessNetworkMessage(connection.Socket); 
 if (msg != null)
        if (msg != null) {
        { this.ProcessMessage(msg, connection);
            this.ProcessMessage(msg, connection); }
        } else
        else {
        { Console.WriteLine("Error appears due processing network message!");
            Console.WriteLine("Error appears due processing network message!"); COM.Handler.LogHandler.Error("Error appears due processing network message!");
            COM.Handler.LogHandler.Error("Error appears due processing network message!"); }
        } }
    } catch (OutOfMemoryException ex)
    catch (OutOfMemoryException ex) {
    { 
        
 }
    } catch (Exception ex)
    catch (Exception ex) {
    { 
        

 }
    } finally
    finally {
    { connection.Socket.Close();
        connection.Socket.Close(); lock (this.connections)
        lock (this.connections) this.connections.Remove(connection);
            this.connections.Remove(connection); }
    } }
}

这里只调用了COM.Handler.NetworkMessage().ProcessNetworkMessage()方法将客户端发过来的内容还原为IndexusMessage 对象,然后交给ProcessMessage()方法处理:
 private void ProcessMessage(COM.IndexusMessage msg, ConnectionInfo connection)
private void ProcessMessage(COM.IndexusMessage msg, ConnectionInfo connection) {
{ 
    

 // check status first [Request || Response]
    // check status first [Request || Response] switch (msg.Status)
    switch (msg.Status) {
    { case COM.IndexusMessage.StatusValue.Request:
        case COM.IndexusMessage.StatusValue.Request: {
            { request case request case
                request case request case }
            } case COM.IndexusMessage.StatusValue.Response:
        case COM.IndexusMessage.StatusValue.Response: {
            { 
                
 }
            } }
    } 
 }
}

这里分类对消息进行处理,如添加到缓存或移除等。下面仔细看下Add分支:
 case COM.IndexusMessage.ActionValue.Add:
case COM.IndexusMessage.ActionValue.Add: {
    { Add Case Add Case
        Add Case Add Case }
    }

主要完成了4个功能:1.将数据保存到LocalCache中;2.如果要缓存的对象设置有过期时间,则在expire中保存一份存根;3.如果配置有复制服务器,则分发到各兄弟节点;4.如果缓存对象超出了最大值,则使用配置的策略靖仓。LocalCache是MergeSystem.Indexus.WinServiceCommon.Cache类型的静态成员,expire是WinServiceCommon.CacheExpire类型的静态成员。
分析到这里,ShartCache的大概思路已经很清晰了。
ShartCache的核心是MergeSystem.Indexus.WinServiceCommon.Cache和MergeSystem.Indexus.WinServiceCommon.CacheExpire这二个类。WinServiceCommon.Cache中使用一个字典对象readonly Dictionary<string, byte[]> dict;来存储需要缓存的数据,因为要缓存的数据都已经序列化通过TCP传输过来,这里就直接保存byte[]类型的了。WinServiceCommon.CacheExpire类中也有一个字典对象private static Dictionary<string, DateTime> expireTable = null;所有设置有过期时间的缓存对象,都在这里有个存根,过期的缓存有WinServiceCommon.CacheExpire负责清除。
来源:wuchang.cnblogs.com




 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号