WCF 服务器/客户端回调,从客户端到服务器的回复
本文关键字:客户端 服务器 回复 回调 WCF | 更新日期: 2023-09-27 18:31:46
在我的客户端/服务器应用程序中,我想计算每个人客户端中的其他值。我使用回调进行了应用程序,但出了点问题。当我想要调用方法pipeproxy.polacz(S);
时,我得到异常,该方法现在获取服务器值并写入服务器控制台。
例外情况是:
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.
另一个问题是,所有客户端的这种功能的总和如何。例;
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) 上对方法进行服务器调用 INSIDE 吗?
-
如果您确实需要此行为,那么您可以通过在回调接口上标记klient_licz调用 OneWay 来解决问题。 这意味着服务器对回调的调用不会阻塞,直到客户端返回(这是当前导致问题的原因,因为服务器正在等待客户端调用返回,但客户端调用正在等待对服务器的调用):
[ServiceContract] public interface ImessageCallback { [OperationContract(IsOneWay = true)] void klient_licz(int a, int b); }
-
或者,您可以使用默认模式 Single 以外的并发模式标记回调暗示。 例如,重入如下所示 - 但请记住,这意味着对回调的调用不会很快编接到 UI thead 即将在线程池线程上,因此您必须调度以更新回调接口上的 UI from 方法:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)] class clients : ImessageCallback, IDisposable { ... }
如果你想了解并发模式以及它如何影响执行,那么你真的需要做一些背景阅读,因为它确实有点复杂 - 但如果你没有这个背景,很难真正理解当你改变并发模式时会发生什么。 这篇 dasBlonde 博客文章很好地总结了不同的模式和行为 - 但您可能希望从一些更面向初学者的教程开始。