WCF服务器/客户端回调,从客户端到服务器的响应 [英] WCF server/client callbacks, reply from client to server

查看:154
本文介绍了WCF服务器/客户端回调,从客户端到服务器的响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的客户端/服务器应用程序中,我想要在每个客户端计算其他值。
我使用回调应用程序,但有些问题。我得到异常,当我想要调用方法 pipeproxy.polacz(S); 哪个获得值服务器,现在写入服务器控制台。

In my client/server application, I want count other value in everyone client. I made application using callbacks, but something is wrong. I get Exception, when I want call method pipeproxy.polacz(S); Which get value to server and write in server console now.

异常为:

此操作会死锁,因为无法接收回复当前消息完成处理。如果要允许乱序消息处理,请在CallbackBehaviorAttribute上指定ConcurrencyMode of Reentrant或Multiple。

其他问题是,在所有客户的反馈。
example;

Other problem is, how sum resault in this funkction from all clients. example;

client 1: S = 1;  
client 2: S = 2;  
client 3: S = 3;

此函数取得所有客户端的结果,并求和。因此,服务器将在服务器控制台中写入6。

And this function take result from all clients and sum it. So server will write 6 in server console.

我的应用程序代码:

服务器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;

namespace WCFapp
{
    class Program
    {
        static void Main(string[] args)
        {
            Klienci cust = new Klienci();
            cust.Connect();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interface;

namespace WCFapp
{
     [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class Klienci : IMessage
{
    private static List<ImessageCallback> subscribers =
        new List<ImessageCallback>();

    public void lista()
    {
        string nm = Console.ReadLine();
        if (nm == "1")
        {
            Console.WriteLine("Number of conected clients: " + subscribers.Count());
            funkcja();

        }
    }

    public void Connect()
    {
        using (ServiceHost host = new ServiceHost(
            typeof(Klienci), new Uri("net.tcp://localhost:8000")))
        {
            host.AddServiceEndpoint(typeof(IMessage),
                new NetTcpBinding(), "ISubscribe");

            try
            {
                host.Open();
                lista();
                Console.ReadLine();
                host.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }

    public bool Subscribe()
    {
        try
        {
            ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>();
            if (!subscribers.Contains(callback))
                subscribers.Add(callback);
            Console.WriteLine("Client is conected ({0}).", callback.GetHashCode());
            return true;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            return false;
        }
    }

    public bool Unsubscribe()
    {
        try
        {
            ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>();
            if (subscribers.Contains(callback))
                subscribers.Remove(callback);
            Console.WriteLine("Client is unconected ({0}).", callback.GetHashCode());
            return true;
        }
        catch
        {
            return false;
        }
    }

    public void funkcja()
    {
        int a = 1; int b = 3;
        subscribers.ForEach(delegate(ImessageCallback callback)
        {
            if (((ICommunicationObject)callback).State == CommunicationState.Opened)
            {
            Console.WriteLine("a= {0} , b= {1}", a, b);
            callback.klient_licz(a, b);
            a++;
            b++;
            }
        });

    }

    public void polacz(int S)
    {

        Console.WriteLine("Sum: {0}", S);
    }
  }
}

接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;


namespace Interface
{
     [ServiceContract(CallbackContract = typeof(ImessageCallback), SessionMode = SessionMode.Required)]
public interface IMessage
{
    [OperationContract]
    void funkcja();

    [OperationContract]
    void polacz(int S);

    [OperationContract]
    bool Subscribe();

    [OperationContract]
    bool Unsubscribe();

}
[ServiceContract]
public interface ImessageCallback
{
    [OperationContract]
    void klient_licz(int a, int b);
}

}

客户:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            clients cl = new clients();
            if (cl.Conect() == true)
            {
                string tmp = Console.ReadLine();
                while (tmp != "EXIT")
                {
                    cl.SendMessage(tmp);
                    tmp = Console.ReadLine();
                }

            }
             cl.Close();
             Environment.Exit(0);
       }
   }
}

b
$ b

.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;

namespace Client
{
    class clients : ImessageCallback, IDisposable
    {
        IMessage pipeProxy = null;
        public bool Conect()
        {
            DuplexChannelFactory<IMessage> pipeFactory =
                new DuplexChannelFactory<IMessage>(
                    new InstanceContext(this),
                    new NetTcpBinding(),
                    new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));
            try
            {
                pipeProxy = pipeFactory.CreateChannel();
                pipeProxy.Subscribe();
               return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }

        }

        public void Close()
        {
            pipeProxy.Unsubscribe();
        }


        public void klient_licz(int a, int b)
        {
            int S = a + b;
            Console.WriteLine("Sum= {0}", S);
            pipeProxy.polacz(S); //ERROR
        }

    }
}


推荐答案

这里的问题是,在你的回调方法klient_licz(由服务器调用),你正在进行另一个服务器调用。这不允许您的合同当前设置的方式。

The issue here is that inside your callback method klient_licz (which is called by the server) you are making another server call. This is not allowed the way your contracts are currently setup.


  1. 检查您确实需要此行为。你真的需要在回调接口(klient_licz)上做一个服务器调用INSIDE一个方法。

  1. Check you really need this behaviour. Do you really need to make a server call INSIDE a method on the callback interface (klient_licz).

如果您确实需要此行为,那么您可以通过在回调接口上标记klient_licz调用OneWay来解决问题。这意味着对于回调的服务器调用不会阻塞,直到客户端返回(这是当前导致您的问题,因为服务器正在等待客户端调用返回,但客户端调用正在等待对服务器的调用):

If you do need this behaviour then you might be able to fix things by marking the klient_licz call OneWay on the callback interface. That will mean that server call to the callback will not block until the client returns (which is what is currently causing your issue because the server is waiting for the client call to return but the client call is waiting on a call to the server):

[ServiceContract]  
public interface ImessageCallback {  
        [OperationContract(IsOneWay = true)]  
        void klient_licz(int a, int b);  
}


  • 或者,您可以使用并发模式标记回调暗示默认模式为单。例如,可重入如下 - 但要记住,这意味着调用回调不会长期编组到UI的线程,即将在线程池线程,所以你必须派遣更新UI从回调接口上的方法:

  • Alternatively you could mark the callback implimentation with a concurrancy mode other than the default mode Single. Eg Reentrant as follows - but bear in mind that this means that calls to callback will not long be marshalled to the UI thead ie will be on threadpool threads so you would have to dispatch to update the UI from method on the callback interface:

    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]  
    class clients : ImessageCallback, IDisposable {  
     ...
    }
    


  • 理解ConcurrencyMode以及它如何影响执行,那么你真的需要做一些地面读取,因为它确实有点复杂 - 但是如果你没有这样的背景,很难真正理解当你改变ConcurrencyMode时发生什么。此 dasBlonde博客帖子有一个很好的摘要不同的模式和行为 - 但你可能想从一些更有点初学者导向的教程开始。

    If you want to understand ConcurrencyMode and how it effects execution then you will really need to do someback ground reading as it does get a little complicated - but if you dont have that background it is difficult to really understand what is happen when you change the ConcurrencyMode. This dasBlonde blog post has a good summary of the different modes and behaviour - but you might want to start with some tutorials that are a bit more beginner orientated.

    这篇关于WCF服务器/客户端回调,从客户端到服务器的响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆