首页 > 解决方案 > 在 Mono Mac 上调用 WCF 客户端通道上的 Close() 超时,但在 Windows 上有效

问题描述

我有一个使用 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));

标签: c#.netwcfmono

解决方案


You're running on the latest version of Mono to see if there are any problems.

If this fails,I suggest you upload a complete bug record of the test to: https://bugzilla.xamarin.com/

Thanks.


推荐阅读