WCF服务器/客户端回调,从客户端到服务器的回复
在我的客户端/服务器应用程序中,我希望在所有人客户端中计数其他值。 我用回调做了应用程序,但有些地方是错误的。我得到异常,当我想要调用方法pipeproxy.polacz(S);
现在,它获得服务器的价值,并在服务器控制台中写入。WCF服务器/客户端回调,从客户端到服务器的回复
的例外是:
This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute.
另一个问题是,在和所有的客户这个funkction如何resault。 例子;
client 1: S = 1;
client 2: S = 2;
client 3: S = 3;
而且这个函数从所有的客户端取得结果并对其进行求和。所以服务器将在服务器控制台中写入6。
我的应用程序代码:
服务器:
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);
}
}
}
。
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(由服务器调用)中,您正在进行另一个服务器调用。这是不允许的,因为你的合同目前正在建立。
检查你是否真的需要这种行为。你是否真的需要在回调接口(klient_licz)上的一个方法内进行服务器调用。
-
如果您确实需要这种行为,那么您可以通过在回调接口上标记klient_licz调用OneWay来解决问题。这将意味着服务器对回调的调用不会阻塞,直到客户端返回(这是当前导致问题的原因,因为服务器正在等待客户端调用返回,但客户端调用正在等待服务器的调用):
[ServiceContract] public interface ImessageCallback { [OperationContract(IsOneWay = true)] void klient_licz(int a, int b); }
-
另外,您可以用标记比默认模式单以外的concurrancy模式回调执行力度。例如Reentrant,如下所示 - 但请记住,这意味着对回调的调用不会长时间集中到UI上,即,它将位于线程池线程上,因此您必须调度以从回调接口上的方法更新UI:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)] class clients : ImessageCallback, IDisposable { ... }
如果您想了解ConcurrencyMode以及它如何影响执行,那么你将真正需要做的someback地阅读,因为它确实变得有点复杂 - 但如果你没有这样的背景下,很难真正理解当您更改并发模式时会发生什么情况。这dasBlonde blog post有一个很好的摘要的不同模式和行为 - 但你可能想要开始一些教程,这是一个更多的初学者为导向。
另外,在服务上,UseSynchronizationContext必须是false – 2013-04-23 08:44:08
您是否读过异常消息? – 2012-04-21 18:43:11
是的,我读过了,但我不明白这一点... Mayby ...我现在没有多少英文;( – user1031034 2012-04-21 19:58:21