zoukankan      html  css  js  c++  java
  • 负载均衡时,在State_Server模式中的Session共享问题(不讨论负载均衡的问题)

    前言:

    配置Session的mode为State_Server模式,不说明,请按照如下配置

    <sessionState mode="StateServer" stateConnectionString="tcpip=192.168.224.1:42424"cookieless="true" cookieName="APSNET_SessionId" timeout="6000" ></sessionState>

    红色部分是关键部分,上面的ip是我的虚拟机的ip地址。

    通过services.msc找到ASP.Net状态服务,并且开启,然后到注册表中打开AllowRemoteConnection值,设置成1.注册表地址:自己去网上搜吧,太长了不写了。


    以上内容是网上大部分的内容,然后你都做好了,也未必就能Session共享。不信你去试试。(不要给我拿两个浏览器去查询,然后问我为啥不共享,我要咬人的)


    补充:关于负载均衡的配置我是使用nginx做的测试,刚刚使用这个工具,还不是很熟练,你可以在网上找到。至于webFrame嘛,装起来真TMD麻烦。


    正文

    废话说了一大堆,上正文吧。

    以上的配置都做好了之后需要检查你的iis配置,网站的应用程序池和网站的id是否相同,一定要保证相同。

    那么还有一个很重要的就是要修改你的global.asax文件,添加如下代码

        public override void Init()
        {
            base.Init();
            foreach (string moduleName in this.Modules)
            {
                string appName = "APPNAME";
                IHttpModule module = this.Modules[moduleName];
                SessionStateModule ssm = module as SessionStateModule;
                if (ssm != null)
                {
                    System.Reflection.FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                    SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm);
                    if (store == null)//In IIS7 Integrated mode, module.Init() is called later
                    {
                        System.Reflection.FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
                        HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
                        System.Reflection.FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                        appNameInfo.SetValue(theRuntime, appName);
                    }
                    else
                    {
                        Type storeType = store.GetType();
                        if (storeType.Name.Equals("OutOfProcSessionStateStore"))
                        {
                            System.Reflection.FieldInfo uribaseInfo = storeType.GetField("s_uribase", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
                            uribaseInfo.SetValue(storeType, appName);
                        }
                    }
                }
            }
        }



    一切就绪,然后就嗨起来吧,真的可以了。我再这里不上截图了,附件将源码带上(其中包括网站项目、mvc项目和网站应用,都需要配置global文件)。


    如果一切到这里就结束了,好像也能接受,但是我告诉你,我们还没完呢

    通过上面的代码我们可以看到主要思路就是 HttpRuntime的_appDomainAppId属性赋值或者是给OutOfProcSessionStateStore的s_uribase赋值。

    我们通过查看.net源码发现这两个属性都是私有属性,在我的源码附件中的mvc项目中可以看到,在不同的机器和iis版本下,输出的内容不一致,这个内容就是存储session库的一个关键值。

    以下是我查看到的部分源码,抛出来给大家打打牙祭。

    void OneTimeInit() {
                SessionStateSection config = RuntimeConfig.GetAppConfig().SessionState;
     
                s_configPartitionResolverType = config.PartitionResolverType;
                s_configStateConnectionString = config.StateConnectionString;
                s_configStateConnectionStringFileName = config.ElementInformation.Properties["stateConnectionString"].Source;
                s_configStateConnectionStringLineNumber = config.ElementInformation.Properties["stateConnectionString"].LineNumber;
                s_configCompressionEnabled = config.CompressionEnabled;
     
                if (_partitionResolver == null) {
                    String stateConnectionString = config.StateConnectionString;
     
                    SessionStateModule.ReadConnectionString(config, ref stateConnectionString, "stateConnectionString");
     
                    s_singlePartitionInfo = (StateServerPartitionInfo)CreatePartitionInfo(stateConnectionString);
                }
                else {
                    s_usePartition = true;
                    s_partitionManager = new PartitionManager(new CreatePartitionInfo(CreatePartitionInfo));
                }
     
                s_networkTimeout = (int)config.StateNetworkTimeout.TotalSeconds;
     
                string appId = HttpRuntime.AppDomainAppId;
                string idHash = Convert.ToBase64String(CryptoUtil.ComputeSHA256Hash(Encoding.UTF8.GetBytes(appId)));
     
                // Make sure that we have a absolute URI, some hosts(Cassini) don't provide this.
                if (appId.StartsWith("/", StringComparison.Ordinal)) {
                    s_uribase = appId + "(" + idHash + ")/";
                }
                else {
                    s_uribase = "/" + appId + "(" + idHash + ")/";
                }
     
                // We only need to do this in one instance
                s_onAppDomainUnload = new EventHandler(OnAppDomainUnload);
                Thread.GetDomain().DomainUnload += s_onAppDomainUnload;
     
                s_oneTimeInited = true;
            }

     通过上面红色的代码,我们可以看到,不管是在global中赋值给哪个变量,最后都汇集到s_uribase这个变量中。那我们继续找,看一下是在哪里使用到了这个变量吧

    void MakeRequest(
                    UnsafeNativeMethods.StateProtocolVerb   verb,
                    String                                  id,
                    UnsafeNativeMethods.StateProtocolExclusive    exclusiveAccess,
                    int                                     extraFlags,
                    int                                     timeout,
                    int                                     lockCookie,
                    byte[]                                  buf,
                    int                                     cb,
                    int                                     networkTimeout,
                    out UnsafeNativeMethods.SessionNDMakeRequestResults results) {//笔者注:这是一个很重要的out参数
     
                int                         hr;
                string                      uri;
                OutOfProcConnection         conn = null;
                HandleRef                   socketHandle;
                bool                        checkVersion = false;
     
                Debug.Assert(timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES");
     
                SessionIDManager.CheckIdLength(id, true /* throwOnFail */);
     
                if (_partitionInfo == null) {
                    Debug.Assert(s_partitionManager != null);
                    Debug.Assert(_partitionResolver != null);
     
                    _partitionInfo = (StateServerPartitionInfo)s_partitionManager.GetPartition(_partitionResolver, id);
     
                    // If its still null, we give up
                    if (_partitionInfo == null) {
                        throw new HttpException(SR.GetString(SR.Bad_partition_resolver_connection_string, "PartitionManager"));
                    }
                }
     
                // Need to make sure we dispose the connection if anything goes wrong
                try {
                    conn = (OutOfProcConnection)_partitionInfo.RetrieveResource();
                    if (conn != null) {
                        socketHandle = new HandleRef(this, conn._socketHandle.Handle);
                    }
                    else {
                        socketHandle = new HandleRef(this, INVALID_SOCKET);
                    }
     
                    if (_partitionInfo.StateServerVersion == -1) {
                        // We don't need locking here because it's okay to have two
                        // requests initializing s_stateServerVersion.
                        checkVersion = true;
                    }
     
                    Debug.Trace("OutOfProcSessionStateStoreMakeRequest",
                                "Calling MakeRequest, " +
                                "socket=" + (IntPtr)socketHandle.Handle +
                                "verb=" + verb +
                                " id=" + id +
                                " exclusiveAccess=" + exclusiveAccess +
                                " timeout=" + timeout +
                                " buf=" + ((buf != null) ? "non-null" : "null") +
                                " cb=" + cb +
                                " checkVersion=" + checkVersion +
                                " extraFlags=" + extraFlags);
     
                    // Have to UrlEncode id because it may contain non-URL-safe characters
                    uri = HttpUtility.UrlEncode(s_uribase + id);//笔者注:在这里使用到了s_uribase
     		//笔者注:在这里使用uri和主方法的out参数作为参数调用了另外一个方法,并且返回了一个int类型,到此可以看到 hr 对我们的价值已经没有了,我们进入到这个方法看看吧。	
                    hr = UnsafeNativeMethods.SessionNDMakeRequest(
                            socketHandle, _partitionInfo.Server, _partitionInfo.Port, _partitionInfo.ServerIsIPv6NumericAddress /* forceIPv6 */, networkTimeout, verb, uri,
                            exclusiveAccess, extraFlags, timeout, lockCookie,
                            buf, cb, checkVersion, out results);
     
                    Debug.Trace("OutOfProcSessionStateStoreMakeRequest", "MakeRequest returned: " +
                                "hr=" + hr +
                                " socket=" + (IntPtr)results.socket +
                                " httpstatus=" + results.httpStatus +
                                " timeout=" + results.timeout +
                                " contentlength=" + results.contentLength +
                                " uri=" + (IntPtr)results.content +
                                " lockCookie=" + results.lockCookie +
                                " lockDate=" + string.Format("{0:x}", results.lockDate) +
                                " lockAge=" + results.lockAge +
                                " stateServerMajVer=" + results.stateServerMajVer +
                                " actionFlags=" + results.actionFlags);
     
                    if (conn != null) {
                        if (results.socket == INVALID_SOCKET) {
                            conn.Detach();
                            conn = null;
                        }
                        else if (results.socket != socketHandle.Handle) {
                            // The original socket is no good.  We've got a new one.
                            // Pleae note that EnsureConnected has closed the bad
                            // one already.
                            conn._socketHandle = new HandleRef(this, results.socket);
                        }
                    }
                    else if (results.socket != INVALID_SOCKET) {
                        conn = new OutOfProcConnection(results.socket);
                    }
     
                    if (conn != null) {
                        _partitionInfo.StoreResource(conn);
                    }
                }
                catch {
                    // We just need to dispose the connection if anything bad happened
                    if (conn != null) {
                        conn.Dispose();
                    }
     
                    throw;
                }
     
                if (hr != 0) {
                    HttpException e = CreateConnectionException(_partitionInfo.Server, _partitionInfo.Port, hr);
     
                    string phase = null;
     
                    switch (results.lastPhase) {
                    case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Initialization:
                        phase = SR.GetString(SR.State_Server_detailed_error_phase0);
                        break;
     
                    case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.Connecting:
                        phase = SR.GetString(SR.State_Server_detailed_error_phase1);
                        break;
     
                    case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.SendingRequest:
                        phase = SR.GetString(SR.State_Server_detailed_error_phase2);
                        break;
     
                    case (int)UnsafeNativeMethods.SessionNDMakeRequestPhase.ReadingResponse:
                        phase = SR.GetString(SR.State_Server_detailed_error_phase3);
                        break;
     
                    default:
                        Debug.Assert(false, "Unknown results.lastPhase: " + results.lastPhase);
                        break;
                    }
     
                    WebBaseEvent.RaiseSystemEvent(SR.GetString(SR.State_Server_detailed_error,
                                phase,
                                "0x" + hr.ToString("X08", CultureInfo.InvariantCulture),
                                cb.ToString(CultureInfo.InvariantCulture)),
                                this, WebEventCodes.WebErrorOtherError, WebEventCodes.StateServerConnectionError, e);
     
                    throw e;
                }
     
                if (results.httpStatus == 400) {
                    if (s_usePartition) {
                        throw new HttpException(
                            SR.GetString(SR.Bad_state_server_request_partition_resolver,
                                        s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture)));
                    }
                    else {
                        throw new HttpException(
                            SR.GetString(SR.Bad_state_server_request));
                    }
                }
     
                if (checkVersion) {
                    _partitionInfo.StateServerVersion = results.stateServerMajVer;
                    if (_partitionInfo.StateServerVersion < WHIDBEY_MAJOR_VERSION) {
                        // We won't work with versions lower than Whidbey
                        if (s_usePartition) {
                            throw new HttpException(
                                SR.GetString(SR.Need_v2_State_Server_partition_resolver,
                                            s_configPartitionResolverType, _partitionInfo.Server, _partitionInfo.Port.ToString(CultureInfo.InvariantCulture)));
                        }
                        else {
                            throw new HttpException(
                                SR.GetString(SR.Need_v2_State_Server));
                        }
                    }
                }
            }

         下面是SessionNDMakeRequest方法的源代码,很明显在上面使用了这个方法,

        [DllImport(ModName.ENGINE_FULL_NAME, CharSet=CharSet.Ansi, BestFitMapping=false, ThrowOnUnmappableChar=true)]
            internal static extern int SessionNDMakeRequest(
                    HandleRef               socket,
                    string                  server,
                    int                     port,
                    bool                    forceIPv6,
                    int                     networkTimeout,
                    StateProtocolVerb       verb,
                    string                  uri,
                    StateProtocolExclusive  exclusive,
                    int                     extraFlags,
                    int                     timeout,
                    int                     lockCookie,
                    byte[]                  body,
                    int                     cb,
                    bool                    checkVersion,
                    out SessionNDMakeRequestResults results);


    真的要到此为止,往下也找不到了,也看不懂了,等到高手来指导,说的就是你,不要走,告诉我这是为什么  ^_^!!!


    源码在这里点击下崽哟

  • 相关阅读:
    2.5星|《无条件增长》:管理学常识+一些自己的管理案例
    3.5星|《壹棉壹世界》:棉花引发罪恶的黑奴贸易,影响美国南北战争
    只运行一个exe应用程序的使用案例
    WPF中使用WPFMediaKit视频截图案例
    Meta http-equiv属性详解
    层级数据模板 案例(HierarchicalDataTemplateWindow)
    ApplicationCommands 应用程序常见命令
    mvvm command的使用案例
    MatserDetail自动展开
    键盘焦点和逻辑焦点(Logic Focus与Keyboard Focus )
  • 原文地址:https://www.cnblogs.com/xiaoch/p/13417970.html
Copyright © 2011-2022 走看看