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()呼び出しで停止しています。

1分後、クライアントはJITを取得しますが、TimeoutException 同時にメッセージボックスメッセージが表示されます。

したがって、明らかに、コマンドがすぐに送信されるだけでなく、コールバックが正しく呼び出されます。では、なぜタイムアウト例外が発生するのですか?

:MessageBox呼び出しを削除しても、この問題が発生するため、GUIがコールバック応答をブロックする問題ではありません。

4

2 に答える 2

4

コールバックインターフェイスを実装するクライアントクラスに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 に答える