在 Mono Mac 上调用 WCF 客户端通道上的 Close() 超时,但在 Windows 上有效

Posted

技术标签:

【中文标题】在 Mono Mac 上调用 WCF 客户端通道上的 Close() 超时,但在 Windows 上有效【英文标题】:Calling Close() on WCF client channel times out on Mono Mac but works on Windows 【发布时间】:2021-09-25 06:20:18 【问题描述】:

我有一个使用 NetTCP 绑定在 Windows(.Net 框架 4.8)上运行的 WCF 服务器。我有 Windows 和 Mac 客户端。 Windows 和 Mac 客户端使用相同的代码。 Windows 客户端在 .Net framework 4.8 上运行,Mac 客户端在 Mono 6.12.0.122 上运行。

客户端很简单:

连接到服务器 在服务器上调用命令 关闭与服务器的连接

它在 Windows 客户端上运行良好,但在 Mac 客户端上,对 Close() 的调用总是在 1 分钟后超时。注意:在这两种情况下,服务器在从客户端发送后立即看到断开连接。

为什么在 Mac 客户端调用 Close() 会超时,即使它与 Windows 客户端的代码相同?

非常感谢任何关于为什么会发生这种情况的建议。

客户端代码:

ChannelFactory<IMyServerInterface> channelFactory;
internal IMyServerInterface channel;


internal MyConnection(string serverIPAddress, int serverPort)

    this.serverIPAddress = serverIPAddress;
    this.serverPort = serverPort;
    try
    
        NetTcpBinding binding = new NetTcpBinding
        
            SendTimeout = TimeSpan.FromSeconds(120),
            CloseTimeout = TimeSpan.FromSeconds(20),
            Security = new NetTcpSecurity
            
                Mode = SecurityMode.None,
            ,
        ;
        InstanceContext instanceContext = new InstanceContext(this);
        EndpointAddress endpointAddress = new EndpointAddress($"net.tcp://serverIPAddress:serverPort");
        channelFactory = new DuplexChannelFactory<IMyServerInterface>(instanceContext, binding, endpointAddress);
    
    catch (Exception ex)
    
        Log.File.Debug(ex, "WCF exception");
    



internal void Connect()

    channel = channelFactory?.CreateChannel();

    ((IContextChannel)channel).Closed += (sender, e) =>  OnConnectionLost("Connection closed", CommunicationState.Closed); ;
    ((IContextChannel)channel).Faulted += (sender, e) =>  OnConnectionLost("Connection faulted", CommunicationState.Faulted); ;

    Log.File.Debug("Calling HandShake..");
    Result res = channel?.HandShake();
    if (res?.Success == true)
    
        Log.File.Debug($"Connected to server at serverIPAddress:serverPort");
    
    else
    
        throw new Exception("Handshake to server failed" + (res == null? "": $": res.Description"));
    



internal void CloseChannel()

    Log.File.Debug($"CloseChannel");
    var channelRef = (ICommunicationObject)channel;
    channel = null;

    if (channelRef != null)
    
        try
        
            Log.File.Debug($"CloseChannel: Calling Close() on channel");
            channelRef.Close();
        
        catch (Exception ex)
        
            Log.File.Debug($"CloseChannel: ex.GetType(): ex.Message");
            Log.File.Debug($"CloseChannel: Calling Abort() on channel");
            channelRef.Abort();
        
    
    Log.File.Debug($"CloseChannel finished");

我的客户有以下行为:

[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single, AutomaticSessionShutdown = true)]

我的服务有以下行为:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, AutomaticSessionShutdown = true, IncludeExceptionDetailInFaults = true) ]

调用 MyConnection()、Connect()、CloseChannel() 会导致:

2021-07-16 12:30:10.9576 | Calling HandShake..
2021-07-16 12:30:11.6284 | Connected to server at 192.168.10.2:5154
2021-07-16 12:30:11.6644 | CloseChannel
2021-07-16 12:30:11.6648 | CloseChannel: Calling Close() on channel
2021-07-16 12:31:11.6746 | CloseChannel: System.TimeoutException: The operation has timed out.   <-- Why??!
2021-07-16 12:31:11.6762 | CloseChannel: Calling Abort() on channel
2021-07-16 12:31:11.6807 | OnConnectionLost: Connection closed
2021-07-16 12:31:11.6811 | CloseChannel  finished

我不确定这是否相关,但在 Windows 和 Mac 客户端上运行 Wireshark 表明,当连接关闭时,Windows 客户端向服务器发送 TCP RST,而 Mac 客户端向服务器发送 FIN(并且服务器用它自己的 FIN 回复):

窗户:

苹果:

次要问题是未应用以下 CloseTimeout 设置(默认为 1 分钟后超时):

CloseTimeout = TimeSpan.FromSeconds(20)

但是,如果我在 Close() 的参数中设置它,即改变它,它确实会被应用:

channelRef.Close();

收件人:

channelRef.Close(TimeSpan.FromSeconds(20));

【问题讨论】:

【参考方案1】:

您正在运行最新版本的 Mono,看看是否有任何问题。

如果失败,建议你上传完整的测试bug记录到:https://bugzilla.xamarin.com/

谢谢。

【讨论】:

谢谢@佳瑶。我在github.com/mono/mono/issues/21163 创建了一个错误报告以及一个显示问题的简单示例项目(在 MacOS 上运行的相同代码在通道上调用 Close() 时挂起)。 如果任何查看此线程的人想查看 github 链接上的示例项目,我将不胜感激。但是,我只能认为这是 Mono 中的一个错误。 我同意你的看法,感谢你的评论。

以上是关于在 Mono Mac 上调用 WCF 客户端通道上的 Close() 超时,但在 Windows 上有效的主要内容,如果未能解决你的问题,请参考以下文章

使用 mono 2.10.2 在 mod_mono 上安装 WCF

在特定服务器上调用 WCF 服务时,“无法为具有权限的 ssl/tls 建立安全通道”

WCF:无法为 SSL/TLS 安全通道建立信任关系,出现权限错误

重复调用的 WCF 通道生命周期

保持 wcf 回调通道无限期打开/如果出现故障则从客户端重新连接

Wcf 回调网络 tcp 双工仅 1 路故障