WCF 双工通道:检查回调通道是否仍然可用

发布于 2024-08-16 01:29:52 字数 1502 浏览 8 评论 0原文

我有以下问题。我正在写聊天软件。客户端/服务器机制基于WCF的DualHttpBinding。这意味着,如果用户发送消息,则服务器会通知发送该消息的房间中的所有客户端。

我想确保,如果客户端的应用程序崩溃(无论什么原因),客户端对象将从房间列表中删除。

在调用回调操作之前是否可以检查回调通道的状态?问题是,如果我在不再连接的客户端上调用操作(由于意外崩溃),服务将挂起。

 public YagzResult SendMessage(Message message)
    {
        foreach (ChatNodeAddress chatNodeAddress in message.Destination)
        {
            ChatNode chatNode = chatProvider.FindChatNode(chatNodeAddress);
            if (chatNode != null)
            {
                User currentUser = CurrentUser;
                foreach (User user in chatNode)
                {
                    //Don't notify the current client. Deadlock!
                    if (!user.Equals(currentUser))
                    {
                        //Get the callback channel here
                        IYagzClient client = GetClientByUser(user);

                        if (client != null)
                        {
                            //--> If the client here called is not any more available,
                            //the service will hang <---
                            client.OnChatMessageReceived(message);
                        }
                    }
                }
            }
            else
            {
                return YagzResult.ChatNodeNotFound;
            }
        }
        return YagzResult.Ok;
    }

如何检查客户端是否仍在收听?顺便说一句,客户端调用的操作都声明为 OneWay,并且 ConcurrencyMode 设置为“Multiple”。

谢谢大家!

你好,

西蒙

I have the following problem. I'm writing chat software. The client/server mechanism is based on DualHttpBinding of WCF. This means that if a user sends a message, all clients that are in the room where the message has been sent, are notified by the server.

I want to ensure, that if a client's application crashes (whyever), the client object is removed from the rooms' lists.

Is there a possibility to check the callback channel's state before calling a callback operation? The problem is, that if i call an operation on a client which is not anymore connected (because of an unexpected crash), the service will hang.

 public YagzResult SendMessage(Message message)
    {
        foreach (ChatNodeAddress chatNodeAddress in message.Destination)
        {
            ChatNode chatNode = chatProvider.FindChatNode(chatNodeAddress);
            if (chatNode != null)
            {
                User currentUser = CurrentUser;
                foreach (User user in chatNode)
                {
                    //Don't notify the current client. Deadlock!
                    if (!user.Equals(currentUser))
                    {
                        //Get the callback channel here
                        IYagzClient client = GetClientByUser(user);

                        if (client != null)
                        {
                            //--> If the client here called is not any more available,
                            //the service will hang <---
                            client.OnChatMessageReceived(message);
                        }
                    }
                }
            }
            else
            {
                return YagzResult.ChatNodeNotFound;
            }
        }
        return YagzResult.Ok;
    }

How can i check if a client is still listening? BTW, the operations called on the client are all declared OneWay and the ConcurrencyMode is set to "Multiple".

Thank you all!

Greets,

Simon

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

疧_╮線 2024-08-23 01:29:52

您可以将回调合同转换为 ICommunicationObject ,然后检查通道状态。

You can cast callback contract to ICommunicationObject and then check for the channel state.

绿萝 2024-08-23 01:29:52

CommunicationObject(即回调通道)上存在“已关闭”和“故障”的事件。您可能需要为这些添加处理程序并跟踪哪些客户端仍然具有可用的有效通道。

您还可以查看 IChannelInitializer 类来实现客户端跟踪。

There are events on a CommunicationObject (i.e. callback channel) for Closed and Faulted. You may want to add handlers for these and track which clients still have a valid channel available.

You can also take a look at the IChannelInitializer class to implement tracking of clients.

小…楫夜泊 2024-08-23 01:29:52

主要问题是我没有得到任何异常,除了 超时异常。我的服务被阻塞了 1 分钟(我设置的超时),直到引发异常。

我通过以下解决方法解决了这个问题。我没有在服务的当前工作线程上调用客户端回调操作,而是创建了一个新线程来调用客户端回调操作并等待 TimeoutException。如果发生超时,用户将被从他所属的聊天室列表中删除。

这是一个代码片段,展示了我是如何做到的:

首先,我创建了一个类,表示对客户端的单个调用:

class YagzClientAsyncCall<T>
{
    /// <summary> Gets or sets the parameter of the client callback. </summary>
    /// <value> The parameter. </value>
    T Param { get; set; }

    /// <summary> Gets or sets the client. </summary>
    /// <value> The client. </value>
    IYagzClient Client { get; set; }

    /// <summary> Gets or sets the service. </summary>
    /// <value> The service. </value>
    YagzService Service { get; set; }

    /// <summary> Constructor. </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="service"> The service. </param>
    /// <param name="client">  The client. </param>
    /// <param name="param">   The parameter. </param>
    public YagzClientAsyncCall(YagzService service, IYagzClient client, T param)
    {
        Param = param;
        Client = client;
    }

    /// <summary>   
    /// Invokes the client callback. If a timeout exception occurs, 
    /// the client will be removed from clients' list.
    /// </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="clientCallback">   The client callback. </param>
    protected void Invoke(Action<T> clientCallback)
    {
        try
        {
            if (clientCallback != null)
            {
                clientCallback(Param);
            }
        }
        catch (TimeoutException)
        {
            // Remove the client and the user
            Service.RemoveClient(Client);
        }
    }

    protected void Invoke(object objCallback)
    {
        Invoke(objCallback as Action<T>);
    }

    public void CallOperationAsync(Action<T> clientCallback)
    {
        ParameterizedThreadStart ts = new ParameterizedThreadStart(this.Invoke);
        Thread t = new Thread(ts);
        t.Start(clientCallback);
    }
}

假设以下代码是通知聊天室客户端已写入新消息的方法的一部分:

foreach (User user in chatNode)
{
     // Don't notify the current client. Deadlock!
     if (!user.Equals(currentUser))
     {
         IYagzClient client = GetClientByUser(user);

         if (client != null)
         {
             var asyncCall = new YagzClientAsyncCall<Message>(this, client, message);
             asyncCall.CallOperationAsync(client.OnChatMessageReceived);
         }
     }
 }

我只是创建一个new YagzClientAsyncCall-Object 并让该操作在新线程上调用。

The main problem was that I didn't get any exceptions, except from a TimeoutException. My service was blocked for 1 min (the timeout I set), until the exception was fired.

I resolved this problem through the following workaround. Instead of calling the client callback operation on the current working thread of the service, I created a new thread that calls the client callback operation and waits for a TimeoutException. If the timeout occurs, the user is simply removed from the chatroom lists he belonged to.

This is a code snippet that shows how I did it:

At first I created a class representing a single call to the client:

class YagzClientAsyncCall<T>
{
    /// <summary> Gets or sets the parameter of the client callback. </summary>
    /// <value> The parameter. </value>
    T Param { get; set; }

    /// <summary> Gets or sets the client. </summary>
    /// <value> The client. </value>
    IYagzClient Client { get; set; }

    /// <summary> Gets or sets the service. </summary>
    /// <value> The service. </value>
    YagzService Service { get; set; }

    /// <summary> Constructor. </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="service"> The service. </param>
    /// <param name="client">  The client. </param>
    /// <param name="param">   The parameter. </param>
    public YagzClientAsyncCall(YagzService service, IYagzClient client, T param)
    {
        Param = param;
        Client = client;
    }

    /// <summary>   
    /// Invokes the client callback. If a timeout exception occurs, 
    /// the client will be removed from clients' list.
    /// </summary>
    /// <remarks> Simon, 30.12.2009. </remarks>
    /// <param name="clientCallback">   The client callback. </param>
    protected void Invoke(Action<T> clientCallback)
    {
        try
        {
            if (clientCallback != null)
            {
                clientCallback(Param);
            }
        }
        catch (TimeoutException)
        {
            // Remove the client and the user
            Service.RemoveClient(Client);
        }
    }

    protected void Invoke(object objCallback)
    {
        Invoke(objCallback as Action<T>);
    }

    public void CallOperationAsync(Action<T> clientCallback)
    {
        ParameterizedThreadStart ts = new ParameterizedThreadStart(this.Invoke);
        Thread t = new Thread(ts);
        t.Start(clientCallback);
    }
}

Suppose the following code is part of a method that notifies chatroom clients that a new message was written:

foreach (User user in chatNode)
{
     // Don't notify the current client. Deadlock!
     if (!user.Equals(currentUser))
     {
         IYagzClient client = GetClientByUser(user);

         if (client != null)
         {
             var asyncCall = new YagzClientAsyncCall<Message>(this, client, message);
             asyncCall.CallOperationAsync(client.OnChatMessageReceived);
         }
     }
 }

I just create a new YagzClientAsyncCall-Object and let the operation be called on a new thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文