由于回调WCF导致的死锁 [英] deadlock due to callback WCF

查看:107
本文介绍了由于回调WCF导致的死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在服务器上启动WCF服务后,我将两个不同的 Client 连接到服务器。过了一会儿,客户端都失去了与服务器的连接。这是因为任何问题,如网络适配器崩溃。之后,服务器尝试调用回调函数,但服务器不知道客户端不再存在以响应请求。因此,它导致死锁

有谁知道如何防止这个问题???





After starting the WCF service on the server, I connect two different Clients to the server. After a while, both Clients lose the connection with the server. It is because of any issue such as the network adapter crash. After that, Server try to call the callback function but the server does not know this Client is not existing anymore to respond the request. Therefore, it is cause a deadlock.
Does anyone know how to prevent this issue???


[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public class ChatService : IChat
{
    Dictionary<Client, IChatCallback> clients = new Dictionary<Client, IChatCallback>();

    List<Client> clientList = new List<Client>();

    public IChatCallback CurrentCallback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<IChatCallback>();

        }
    }

    object syncObj = new object();

    private bool SearchClientsByName(string name)
    {
        foreach (Client c in clients.Keys)
        {
            if (c.Name == name)
            {
                return true;
            }
        }
        return false;
    }

    #region IServices Members
    // Public client connection 
    // retern true, when the connection has been established successfully
    // otherwise return false 
    public bool Connect(Client client)
    {
        lock (syncObj)
        {
            // Remove the client if it exists
            RemoveSubscriberByKey(client);

            // Add client with the callback
            AddSubscriber(client);

            OperationContext.Current.Channel.Faulted += new EventHandler(Channel_Faulted);
            OperationContext.Current.Channel.Closed += new EventHandler(Channel_Closed);

            foreach (IChatCallback callback in clients.Values)
            {
                try
                {
                    if (((ICommunicationObject)callback).State == CommunicationState.Opened)
                    {
                        // State is still opened, but actully is not
                        CallMethod(() => callback.RefreshClients(clientList));
                        CallMethod(() => callback.UserJoin(client));
                    }
                    else
                    {
                        RemoveSubscriberByValue(callback);
                    }
                }
                catch
                {
                    RemoveSubscriberByValue(callback);
                    return false;
                }
            }
        }
        return true;
    }

    private void AddSubscriber(Client client)
    {
        clients.Add(client, CurrentCallback);
        clientList.Add(client);
    }

    private void RemoveSubscriber(Client client)
    {
        clients.Remove(client);
        clientList.Remove(client);
    }

    private void RemoveSubscriberByKey(Client client)
    {
        if (clients.Count > 0)
        {
            foreach (var item in clients.Keys.Where(item => item.Name.Equals(client.Name)))
            {
                clients.Remove(client);
                clientList.Remove(client);
            }
        }
    }

    private void RemoveSubscriberByValue(IChatCallback callback)
    {
        if(clients.Values.Contains(callback))
        {
            Client c = clients.FirstOrDefault(x => x.Value == callback).Key;
            clients.Remove(c);
            clientList.Remove(c);
        }
    }

    void Channel_Closed(object sender, EventArgs e)
    {
        IChatCallback machine = sender as IChatCallback;
        RemoveSubscriberByValue(machine);
    }

    void Channel_Faulted(object sender, EventArgs e)
    {
        IChatCallback machine = sender as IChatCallback;
        RemoveSubscriberByValue(machine);
    }

    public void CallMethod(Action methodToBeCalled)
    {
        try
        {
            methodToBeCalled();
        }
        catch (TimeoutException ex)
        {
        }
        catch (CommunicationException ex)
        {
        }
        catch (ObjectDisposedException ex)
        {
        }
        catch (Exception ex)
        {
        }
    }
}

推荐答案

这篇关于由于回调WCF导致的死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆