0

我正在尝试将游戏内控制台连接到 WCF 接口,因此外部应用程序可以发送控制台命令并接收控制台输出。为此,我创建了以下服务合同:

public interface IConsoleNetworkCallbacks
{
    [OperationContract(IsOneWay = true)]
    void NewOutput(IEnumerable<string> text, string category);
}

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IConsoleNetworkCallbacks))]
public interface IConsoleInterface
{
    [OperationContract]
    void ProcessInput(string input);

    [OperationContract]
    void ChangeCategory(string category);
}

在服务器上,我使用以下方法实现了它:

public class ConsoleNetworkInterface : IConsoleInterface, IDisposable
{
    public ConsoleNetworkInterface()
    {
        ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler);
    }

    public void Dispose()
    {
        ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
    }

    public void ProcessInput(string input)
    {
        ConsoleManager.Instance.ProcessInput(input);
    }

    public void ChangeCategory(string category)
    {
        ConsoleManager.Instance.UnregisterOutputHandler(OutputHandler);
        ConsoleManager.Instance.RegisterOutputUpdateHandler(OutputHandler, category);
    }

    protected void OutputHandler(IEnumerable<string> text, string category)
    {
        var callbacks = OperationContext.Current.GetCallbackChannel<IConsoleNetworkCallbacks>();
        callbacks.NewOutput(text, category);
    }
}

在客户端上,我使用以下方法实现了回调:

public class Callbacks : IConsoleNetworkCallbacks
{
    public void NewOutput(IEnumerable<string> text, string category)
    {
        MessageBox.Show(string.Format("{0} lines received for '{1}' category", text.Count(), category));
    }
}

最后,我使用以下类建立服务主机:

public class ConsoleServiceHost : IDisposable
{
    protected ServiceHost _host;

    public ConsoleServiceHost()
    {
        _host = new ServiceHost(typeof(ConsoleNetworkInterface), new Uri[] { new Uri("net.pipe://localhost") });
        _host.AddServiceEndpoint(typeof(IConsoleInterface), new NetNamedPipeBinding(), "FrbConsolePipe");

        _host.Open();
    }

    public void Dispose()
    {
        _host.Close();
    }
}

并在我的客户端上使用以下代码建立连接:

    protected Callbacks _callbacks;
    protected IConsoleInterface _proxy;

    protected void ConnectToConsoleServer()
    {
        _callbacks = new Callbacks();
        var factory = new DuplexChannelFactory<IConsoleInterface>(_callbacks,
            new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/FrbConsolePipe"));
        _proxy = factory.CreateChannel();
        _proxy.ProcessInput("Connected");
    }

所以发生的事情是 myConnectToConsoleServer()被调用,然后它一直到_proxy.ProcessInput("Connected");. 在我的游戏中(在服务器上),我立即看到由ProcessInput调用引起的输出,但客户端仍然停止_proxy.ProcessInput()调用。

一分钟后,我的客户收到了 JIT ,TimeoutException 同时出现了我的 MessageBox 消息。

所以显然不仅我的命令被立即发送,我的回调也被正确调用。那么为什么我会收到超时异常?

注意:即使删除 MessageBox 调用,我仍然有这个问题,所以这不是 GUI 阻止回调响应的问题。

4

2 回答 2

4

您需要为实现 Callback 接口的客户端类指定 CallbackBehavior [CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, UseSynchronizationContext=false)]

请参阅以下内容以获得更好的解释 http://www.switchonthecode.com/tutorials/wcf-callbacks-hanging-wpf-applications

于 2012-10-26T16:59:28.080 回答
2

可能是您_proxy.ProcessInput("Connected")阻止了呼叫 - 这与您的超时经验一致,因为服务器立即发送响应,但客户端无法接收它,因为它卡在“ProcessInput”上。当您的调用最终超时时,阻塞调用终止,此时回调完成。

为了验证这一点,您可以尝试使用此(非阻塞)调用来调用吗?

((Action)(() => _proxy.ProcessInput("Connected"))).BeginInvoke(null, null);
于 2012-08-01T04:24:46.933 回答