WCF 多个客户端阻塞问题!

发布于 2024-08-26 12:46:27 字数 458 浏览 5 评论 0原文

我似乎遇到了 WCF 阻塞问题。

假设我有两个用户,每个用户都使用 net.tcp 创建了自己的在 WCF 主机上公开的类实例,其端点类似于“net.tcp://localhost:32000/SymHost/”。该类是 PerSession 上下文,并发性是可重入的。该类公开了两个方法 Alive(),它们立即返回 true 布尔值,以及我插入的 AliveWait,它在返回 true 之前执行 Thread.Sleep 4 秒(测试目的)。

现在客户端 1 调用 AliveWait() ,在此期间他被阻止,这很公平,但是如果客户端 2 在其自己的实例上调用 Alive(),他必须等到客户端 1 的调用返回 - 这种行为不是我想要的会预料到吗?我希望客户端 2 能够像什么都没发生一样继续运行,或者这是否与它们共享相同的端点有关?

谁能解释一下发生了什么以及我如何确保客户端 2 可以不间断地调用自己的实例?

非常感谢任何帮助!

I seem to have a blocking issue with WCF.

Say I have two users and each have created their own instance of a class exposed on a WCF host using net.tcp with endpoint something like this "net.tcp://localhost:32000/SymHost/". The class is PerSession context and concurrency is reentrant. The class exposes two methods Alive() which return a bool of true straight away and an AliveWait which I inserted which does a Thread.Sleep for 4 seconds before returning true (testing purposes).

Now client 1 calls AliveWait() during which time he is blocked which is fair enough but then if client 2 makes a call to Alive() on its own instance he has to wait until client 1's call is returned - this behaviour is not what I would have expected? I would have expected client 2 to carry on as if nothing has happened or is this to do with the fact that they both share the same endpoint?

Can anyone explain what is going on and how I can make sure that client 2 can call its own instance uninterrupted?

Any help much appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

青春如此纠结 2024-09-02 12:46:27

我发现那是什么了!我忘记在 Test 类的 ServiceBehaviour 中将 UseSynchronizationContext 设置为 false。默认为 true,这会同步服务上的所有调用以在同一线程上运行!因此,来自其他客户端的任何后续呼叫都只是排队!

I found out what it was! I had forgotten to put the UseSynchronizationContext to false in the ServiceBehaviour of the Test class. This defaults to true which synchronises all calls on the service to run on the same thread! So any subsequent calls from other clients were simply queued!

北恋 2024-09-02 12:46:27

向我们展示服务等级!仅从你的描述来看,无法判断到底是怎么回事。

期望客户端 2 被客户端 1 阻止 - 在每个会话场景中,两个客户端都应该获得自己的、完全独立的服务类实例。这就是为什么我们需要查看我们正在处理的代码类型......通常,这种设置不应该有任何问题。

Show us the service class ! Just from your description, it's impossible to tell what's going on.

I would not expect client 2 to be blocked by client 1 - in a per-session scenario, the two clients should each get their own, totally independent service class instances. That's why we need to see what kind of code we're dealing with here.... normally, there should not be any problem with that kind of setup.

情话已封尘 2024-09-02 12:46:27

这正是我的想法!所以这里是一些源代码(经过一些复制和粘贴之后...):

-- 合约定义

[ServiceContract(CallbackContract = typeof(IAliveCallback))]
public interface IAlive 
{
    [OperationContract]
    bool Validate();

    [OperationContract]
    string AliveWait(int i);    // test test
}

-- 在我的 Alive 类中实现合约

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class Alive : SymHostBase, IAlive
{
    private readonly static string _ID = "Alive";
    private static int _MaxAliveWaitSeconds = 5;

    public bool Validate()
    {
        return true;
    }

    public string AliveWait(int i)
    {
        Thread.Sleep(i * 1000);
        return string.Format("I waited {0} seconds", i);
    }

...
...
}

-- 然后在 Host 应用程序上它看起来像这样...

        string s = string.Format("net.tcp://localhost:{0}/Host/", port);
        Uri tcpAddr = new Uri(s);
        Uri[] baseAddress = { tcpAddr };

        int MaxBuffer = 64;     // 64 Mb
        int bufferSize = MaxBuffer * 1024 * 1024;   // 67108864

        NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None, true);
        tcpBinding.MaxBufferPoolSize = bufferSize; // 64 Mb
        tcpBinding.MaxBufferSize = bufferSize;
        tcpBinding.MaxReceivedMessageSize = bufferSize;
        tcpBinding.TransferMode = TransferMode.Buffered;
        tcpBinding.ReaderQuotas.MaxArrayLength = bufferSize;
        tcpBinding.ReaderQuotas.MaxBytesPerRead = bufferSize;
        tcpBinding.ReaderQuotas.MaxStringContentLength = bufferSize;

        tcpBinding.MaxConnections = 100;
        //tcpBinding.ReceiveTimeout = new TimeSpan(20, 0, 0);
        tcpBinding.SendTimeout = new TimeSpan(0, 0, 5);     
        tcpBinding.ReliableSession.Enabled = true;
        tcpBinding.ReliableSession.InactivityTimeout = new TimeSpan(7, 0, 0, 0);    // 7 days


        _HostAlive = new ServiceHost(typeof(Alive), baseAddress);
        _HostAlive.AddServiceEndpoint(typeof(IAlive), tcpBinding, "alive");      // tcpBinding


        ServiceThrottlingBehavior throttle = _HostAlive.Description.Behaviors.Find<ServiceThrottlingBehavior>();
        if (throttle == null)
        {
            throttle = new ServiceThrottlingBehavior();
            host.Description.Behaviors.Add(throttle);
        }
        throttle.MaxConcurrentCalls = 1000;         // default 16
        throttle.MaxConcurrentInstances = 1000;     // default 26
        throttle.MaxConcurrentSessions = 1000;      // default 10 

        // open the host - bring it into life!
        host.Open();

That is exactly what I thought! So here is some of the source code (after bit of copy and pasting...):

-- contract definition

[ServiceContract(CallbackContract = typeof(IAliveCallback))]
public interface IAlive 
{
    [OperationContract]
    bool Validate();

    [OperationContract]
    string AliveWait(int i);    // test test
}

-- implementing the contract in my Alive class

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class Alive : SymHostBase, IAlive
{
    private readonly static string _ID = "Alive";
    private static int _MaxAliveWaitSeconds = 5;

    public bool Validate()
    {
        return true;
    }

    public string AliveWait(int i)
    {
        Thread.Sleep(i * 1000);
        return string.Format("I waited {0} seconds", i);
    }

...
...
}

-- then on the Host app it looks like this...

        string s = string.Format("net.tcp://localhost:{0}/Host/", port);
        Uri tcpAddr = new Uri(s);
        Uri[] baseAddress = { tcpAddr };

        int MaxBuffer = 64;     // 64 Mb
        int bufferSize = MaxBuffer * 1024 * 1024;   // 67108864

        NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.None, true);
        tcpBinding.MaxBufferPoolSize = bufferSize; // 64 Mb
        tcpBinding.MaxBufferSize = bufferSize;
        tcpBinding.MaxReceivedMessageSize = bufferSize;
        tcpBinding.TransferMode = TransferMode.Buffered;
        tcpBinding.ReaderQuotas.MaxArrayLength = bufferSize;
        tcpBinding.ReaderQuotas.MaxBytesPerRead = bufferSize;
        tcpBinding.ReaderQuotas.MaxStringContentLength = bufferSize;

        tcpBinding.MaxConnections = 100;
        //tcpBinding.ReceiveTimeout = new TimeSpan(20, 0, 0);
        tcpBinding.SendTimeout = new TimeSpan(0, 0, 5);     
        tcpBinding.ReliableSession.Enabled = true;
        tcpBinding.ReliableSession.InactivityTimeout = new TimeSpan(7, 0, 0, 0);    // 7 days


        _HostAlive = new ServiceHost(typeof(Alive), baseAddress);
        _HostAlive.AddServiceEndpoint(typeof(IAlive), tcpBinding, "alive");      // tcpBinding


        ServiceThrottlingBehavior throttle = _HostAlive.Description.Behaviors.Find<ServiceThrottlingBehavior>();
        if (throttle == null)
        {
            throttle = new ServiceThrottlingBehavior();
            host.Description.Behaviors.Add(throttle);
        }
        throttle.MaxConcurrentCalls = 1000;         // default 16
        throttle.MaxConcurrentInstances = 1000;     // default 26
        throttle.MaxConcurrentSessions = 1000;      // default 10 

        // open the host - bring it into life!
        host.Open();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文