我有一个asmx web服务,应该只允许一次响应1个客户端。如何确保一次仅调用一次asmx Web服务?
换句话说,如果服务被客户端A调用,并且服务器B调用,我希望B挂起直到A完成,然后B可以得到服务。
如果这太复杂了,那么在B服务期间,来自B的最低限度的呼叫应该会失败,并且在用户定义的错误期间A会发生。
原因是服务在很大程度上依赖于IO操作和XML序列化,因此至关重要的是服务不会被多于一个客户端同时调用。
在此先感谢
我有一个asmx web服务,应该只允许一次响应1个客户端。如何确保一次仅调用一次asmx Web服务?
换句话说,如果服务被客户端A调用,并且服务器B调用,我希望B挂起直到A完成,然后B可以得到服务。
如果这太复杂了,那么在B服务期间,来自B的最低限度的呼叫应该会失败,并且在用户定义的错误期间A会发生。
原因是服务在很大程度上依赖于IO操作和XML序列化,因此至关重要的是服务不会被多于一个客户端同时调用。
在此先感谢
static object _LockObject = new object();
void WebServiceCall()
{
lock(_LockObject)
{
// Do work...
}
}
创建一个静态对象,您可以调用lock()。 lock()
语句将阻止其他调用在内部执行代码,直到获得锁的第一次执行完成。
请注意,取决于您的超时设置,B可能会因超时时间的长短而失败,具体取决于A完成的时间。
更新:是的,你可以使用Monitor类来代替lock()
。您可以使用Monitor.TryEnter()方法来检查对象是否已被锁定(即:如果您想返回错误而不是等待)。
更多细节:
从http://msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx:
形式
lock (x) ...
的lock语句,其中x是一个引用类型的表达式,是恰恰相当于
System.Threading.Monitor.Enter(x);
try {
...
}
finally {
System.Threading.Monitor.Exit(x);
}
从http://msdn.microsoft.com/en-us/library/de0542zz.aspx:
使用Enter获取作为参数传递的对象上的监视器。如果另一个线程在对象上执行了一个Enter,但尚未执行相应的Exit,则当前线程将阻塞,直到另一个线程释放该对象。
所以它只是设计,代码知道阻止和不跳过。如果你想使用Monitor.TryEnter()方法,你可以跳过。
我不知道它是如何在.NET中实现的,但我想你想实现当正在维修它由请求这是“拥有”的锁定对象,不能给一次请求多个请求。在Java中,我可能会同步一些全局对象。
要小心,但要注意常见的并发问题......对于一个天真的实现来说,一个请求检查锁并找到它可用,然后睡觉,然后第二个请求检查锁并接受它,然后第一次请求唤醒,认为锁是免费的,坏事发生)。另外请确保您处理请求处理崩溃并保留锁定的情况。
由于作为一种不好的做法,制定非并发的基于Web的系统的使用模式(当然在Java servlets世界中),我建议你在服务已经存在的情况下抛出一个错误在使用中而不是阻止,因为可能难以判断阻塞的影响。
您的意思是标记一个asp.net全局应用程序变量? – 2010-03-07 18:53:15
就像我说的,我不确定asp.net的详细信息,因为我不使用该语言,但您需要一些可用于所有请求的对象,这些对象可用于宣传请求正在被服务。然后该请求可以检查该对象,并且只有在没有其他请求正在进行时才继续。但要小心,注意死锁的可能性,并确保处理请求处理崩溃而将锁留在原地的情况。 – Brabster 2010-03-07 19:01:40
我不知道你为什么要这样做,但无论如何,这可能是一个有效的方案。尝试查看Linux的APT程序包管理器如何获取锁定:
要防止包管理器的多个实例产生,要使包管理器正常工作,需要锁定锁定文件并将其写入PID。
同样,您可以在虚拟主机的根目录中创建一个文件。当客户端连接时,锁定该文件,然后在其中写入内容。完成后,将文件清空。试图锁定它之前,试着看看里面有没有东西。如果是,则将错误消息返回给客户端。
这是一个很好的答案,但你忘记了一个重要的点 - 重新启动能力。如果ws线程死亡,您如何采取措施确保文件被重置,否则最终可能导致服务调用被锁定到所有客户端。 – 2010-03-07 18:59:52
糟糕!我没有想到这一点。如果客户端没有释放锁定(清除文件),则该人员必须手动清除它。这个问题的第一个答案(上面)是正确的。干杯!! – 2010-03-08 05:18:05
我理解一次只处理一个请求的要求,但我不认为一次只允许一个请求就是答案。
某些答案建议阻止请求。虽然这将小规模工作,但这会导致诸如超时和将缩放到更多服务器的问题。
另一种方法是您在处理每个请求时将其服务并将其放在队列以供稍后处理。该队列可以一次处理一个任务(或者取决于服务器的繁忙程度)。
可以通过几种方式通知原始请求者完成。一种方法是轮询查看原始请求是否已完成,或者是否仍在队列中进行处理,可能使用生成的令牌(如GUID)。
+1鉴于现在有更多信息,我同意排队请求听起来像是正确的想法。 – Brabster 2010-03-07 19:05:14
请原谅我的无知,但这对我来说毫无意义,您能否详细说明一下?谢谢 – 2010-03-07 18:55:01
@JL:增加了一些细节。让我知道你是否有一个具体的问题,你想要更多的细节。 – 2010-03-07 18:58:00
也可以确定对象的锁定状态吗? – 2010-03-07 19:02:53