2 yangyangrenren yangyangrenren 于 2015.07.20 11:14 提问

web service访问数量控制
详细功能:客户端是WPF,服务端是Web Service(C#),客户端请求查询服务器端是否有更新的版本,若有则下载更新。
    开发工具:VS2013,在管理员权限下运行。
    开发及测试环境:IIS6.0,电脑内核数量为4,逻辑处理器数量为8。
    相关参数设置:IIS管理器下设置-应用程序池-网站的最大工作进程数为默认值1.客户端与Web Service的超时时间都是120秒。测试用的更新包大小为3101KB。采用log4net在服务器端记录日志。
    问题描述:由于最终将发布在远程服务器上,带宽有限制,120秒的时间内,最多只能保证大约23个请求成功下载,其他的请求不可能成功。【计算方法:带宽*120秒/3101KB=25个。并且经测试,几乎都是保持在23个请求可以成功下载更新。(附:远程服务器环境为核心数2,线程数2,IIS6.0)】   于是想用Application["CountOnline"]来统计正在请求下载的客户端数量,假设这个数量已经超过了23,如果再有新的下载请求,那么就立刻返回“服务器忙”异常消息;否则就下载更新。每有一次连接请求,那么Application["CountOnline"]值加1;请求结束之后,Application["CountOnline"]值减1。采用多线程同时请求下载来模拟多客户端进行测试。
    1、把web service发布到本地的开发机器的虚拟目录下,发现Application["CountOnline"]的值最大为3,根本不能突破3。注:本地环境下测试,无带宽限制。把Web Service发布到远程服务器上,Application["CountOnline"]最大为1。
    2、若不发布web service,直接在WPF项目下,添加服务引用——发现“解决方案下的服务”,然后运行测试代码,发现Application["CountOnline"]的值最大可以达到8.
    3、修改IIS管理器下设置-应用程序池-网站的最大工作进程数为10,此时若再引用本地的虚拟目录下的服务,Application["CountOnline"]的最大值依然是3,并且由于是最大工作进程数的限制变为10,导致记录的日志信息不完全。同样的,服务器端Application["CountOnline"]最大值依然是1.
    Web Service主要代码如下:
    [WebMethod(Description = "", EnableSession = true)]
    public byte[] LoadFile(string software)
    {
        string filePath = Server.MapPath("Software/") + software;
        FileStream fs = null;
        if (File.Exists(filePath))
        {
            try
            {
                log.Info(String.Format("线程{0}进入请求时候,Application[\"count\"]:{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, Application["CountOnline"]));
                if (!(Application["CountOnline"] == null || (int)Application["CountOnline"] <= 23))
                {
                    throw new SoapException("服务器正忙,请稍后再试!", SoapException.ServerFaultCode);
                }                    
                fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                return ConvertStreamToByteBuffer(fs);
            }
            catch (SoapException ex)
            {
                log.Error(String.Format("---------请求已经达到最大限度。"));
                throw new SoapException("服务器正忙,请稍后再试!", SoapException.ServerFaultCode);
            }
            catch (Exception ex)
            {
                log.Error(String.Format("异常消息:{0}{1}堆栈:{2}{0}相关内容:{3}", ex.Message, Environment.NewLine, ex.StackTrace, ex.ToString()));
                throw new SoapException(ex.ToString(), SoapException.ServerFaultCode);
            }
            finally
            {
              if(fs!=null)
                {
                    fs.Flush();
                    fs.Close();
                }                  
              log.Info(String.Format("线程{0}执行完毕离开时候,Application[\"count\"]:{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, Application["CountOnline"]));
              Session.Abandon();                  
            }
        }
        else
        {
            log.Error(filePath + "文件不存在");
            throw new SoapException(filePath + "文件不存在", SoapException.ServerFaultCode);
        }
    }

            public class Global : System.Web.HttpApplication
{

    protected void Application_Start(object sender, EventArgs e)
    {
        if (Application["CountOnline"] == null)
        {
            Application["CountOnline"] = 0;
        }
        log4net.Config.XmlConfigurator.Configure(new FileInfo("Log4net.config"));
    }

    protected void Session_Start(object sender, EventArgs e)
    {
        Application.Lock();
        int countOnline = (int)Application["CountOnline"];  
        countOnline++;    
        Application["CountOnline"] = countOnline;  
        Application.UnLock();
    }

    protected void Session_End(object sender, EventArgs e)
    {
        Application.Lock();
        int countOnline = (int)Application["CountOnline"];  
        countOnline--;  
        Application["CountOnline"] = countOnline;
        Application.UnLock();
    }
}

    客户端测试代码主要如下:
     try
        {
            for (int i = 0; i <100; i++)
            {
                ThreadWithState tws = new ThreadWithState(i);
                Thread t = new Thread(new ThreadStart(tws.ThreadProc));
                t.Start();
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }




    public class ThreadWithState
{
    private int i;
    public ThreadWithState( int number)
    {
        i = number;
    }
    public void ThreadProc()
    {
        try
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            ServiceReference1.WebService1SoapClient ws;
            binding.MaxReceivedMessageSize = 2147483647;
            binding.MaxBufferPoolSize = 2147483647;
            binding.CloseTimeout = new TimeSpan(0,0,120);
            binding.SendTimeout = new TimeSpan(0, 0, 120);

               ws = new ServiceReference1.WebService1SoapClient(binding, new EndpointAddress(new Uri("http://192.168.1.91:81/WebService1.asmx")));           
            System.Diagnostics.Stopwatch spw = new System.Diagnostics.Stopwatch();
            spw.Start();            
            ws.Open();
            byte[] file = ws.LoadFile("*****文件名****");
            spw.Restart();
            string time = System.DateTime.Now.ToString("_yyyy-MM-dd HH-mm-ss_ffff");
            string downPath = @"c:\download\" + i + "" + time + ".zip";
            FileStream fs = new FileStream(downPath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            fs.Write(file, 0, file.Length);
            fs.Flush();
            fs.Dispose();
            ws.Abort();
            ws.Close();
            Console.WriteLine(i + ",写入磁盘完成耗时:" + spw.ElapsedMilliseconds + ",线程id:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }          
    }
}

    每一个新的请求,那么服务端应该都会新开一个线程,为什么我的服务器端的Application["CountOnline"]始终没有什么变化呢。我猜想是不是IIS或者还有哪个地方没有设置呢?还是我的代码有问题?已经在百度上面查询了好久,没有找到答案。请大家帮忙看看。

2个回答

CSDNXIAOD
CSDNXIAOD   2015.07.20 11:23

如何访问web service
VBA中访问Web Service
----------------------biu~biu~biu~~~在下问答机器人小D,这是我依靠自己的聪明才智给出的答案,如果不正确,你来咬我啊!

bulusli3
bulusli3   Ds   Rxr 2015.07.20 11:37

建议你不要用sessionStart和sessionEnd对Application变量进行增减,而是通过对Application变量加锁的方式进行增减,这样能够保证多线程时Application变量的增减同步。举个例子,定义一个static object obj=new object();
lock(obj){
Application["count"]++;//or --;
}

yangyangrenren
yangyangrenren sessionStart与sessionEnd事件,我在网上看到有资料说他们是线程安全的,但是实验发现并不是的,所以在里面加了锁。我最开始是使用您的建议那样,在进入操作之间加锁加1,操作完成之后加锁减1,但是效果与sessionStart、sessionEnd一样。
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片