WCF 双工 TCP 通信错误

标签 wcf duplex net.tcp

我有一个示例服务来测试 WCF net.tcp 通信。这是一个非常简单的服务,它所做的就是为客户端订阅服务,然后调用回调 channel 来通知所有连接的客户端有关广播的消息。该服务托管在 IIS 7.5 内。

这是服务代码和测试客户端来测试它。

[ServiceContract(CallbackContract = typeof(ISampleServiceCallBack), SessionMode = SessionMode.Required)]
public interface ISampleCuratioService
{
    [OperationContract(IsOneWay = true)]
    void SubcribeToService(string sub);

    [OperationContract]
    string GetData(int value);

    [OperationContract(IsOneWay = true)]
    void Broadcast(string message);
}

public interface ISampleServiceCallBack
{
    [OperationContract(IsOneWay = true)]
    void NotifyClient(string message);
}

这是服务实现:

[ServiceBehavior(Name = "CuratioCSMService", InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : ISampleCuratioService
{
    private static List<ISampleServiceCallBack> JoinedClien = new List<ISampleServiceCallBack>();

    public void SubcribeToService(string sub)
    {
        var subscriber = OperationContext.Current.GetCallbackChannel<ISampleServiceCallBack>();
        if (!JoinedClien.Contains(subscriber))
        {
            JoinedClien.Add(subscriber);
        }
    }

    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }

    public void Broadcast(string message)
    {
        JoinedClien.ForEach(c => c.NotifyClient("message was received " + message));
    }
}

我无法理解运行它时得到的行为。第一个客户端运行后,一切正常,但当我关闭并打开测试客户端应用程序时,它会抛出异常,通知 channel 无法用于通信,因为它处于故障状态。

这是示例测试客户端:

    static void Main(string[] args)
    {
        var callneckclient = new ServiceClientProxy();
        var client = new SampleCuratioServiceClient(new InstanceContext(callneckclient));
        client.SubcribeToService("me");
        Console.ReadLine();

        for (int i = 0; i < 15; i++)
        {
            Console.WriteLine(client.GetData(5));
            client.Broadcast("this is from client me");
        }
        client.Close();
        Console.Read();
    }

    public class ServiceClientProxy : ISampleCuratioServiceCallback, IDisposable
    {
        public void NotifyClient(string message)
        {
            Console.WriteLine(message);
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }
    }

当我运行 5 个客户端时,情况会变得更加糟糕。这些都不能发送或接收消息。

最佳答案

当客户端调用 SubscribeToService 时,您将其操作上下文添加到名为 JoinedClien 的列表中。

当您在服务器中调用 Broadcast 时,您会为曾经连接过的每个客户端调用所有收集的操作上下文上的方法 NotifyClient

问题是,断开连接的客户端不会从您的 JoinedClien 列表中删除。 当您尝试在断开连接的操作上下文上调用操作方法时,您会收到 channel 处于故障状态错误。

要解决此问题,您应该订阅 Channel_ClosedChannel_Faulted 事件,并在回调客户端时捕获 CommunicationException 并删除故障客户端的操作上下文:

public void Broadcast(string message)
{
    // copy list of clients
    List<OperationContext> clientsCopy = new List<OperationContext>();
    lock(JoinedClien) {
        clientsCopy.AddRange(JoinedClien);
    }

    // send message and collect faulted clients in separate list
    List<OperationContext> clientsToRemove = new List<OperationContext>();
    foreach (var c in JoinedClien) 
    { 
        try {
            c.NotifyClient("message was received " + message));
        }
        catch (CommunicationException ex) {
            clientsToRemove.Add(c);
        }
    }

    foreach (var c in clientsToRemove)
    {
        lock(JoinedClien) {
            if(JoinedClien.Contains(c))
                JoinedClien.Remove(c);
        }
    }
}

添加新客户端时,您也必须锁定该操作:

var subscriber = OperationContext.Current.GetCallbackChannel<ISampleServiceCallBack>();
lock(JoinedClien) 
{
    if (!JoinedClien.Contains(subscriber))
    {
        JoinedClien.Add(subscriber);
    }
}

关于WCF 双工 TCP 通信错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8672061/

相关文章:

.net - 日志中的 BinarySecurityToken

c# - 在 IIS 中访问 .svc 文件时出现 HTTP 404

sockets - TCP 是双向的还是全双工的?

wcf - 带有 SSL 证书的 Net.TCP 是否可以在互联网上使用

wcf - Azure WebRole 中的套接字/超时用于与 WorkerRole 中的 WCF 主机进行同步通信

wcf - Windows 服务总线 1.0、Appfabric、Netmessaging 绑定(bind)失败

c++ - Mac(或 C++)连接到二进制 WCF

WCF 双工回调示例失败

WCF绕过防火墙的两种HTTP通信方式

wcf - 使用私钥加入 SSL .crt 证书以用于 WCF 的 Net.Tcp 绑定(bind)