WCF - ReceiveTimeout 似乎没有任何效果

问题描述 投票:0回答:1

我们的安全部门报告说,我们的 WCF 服务没有实现超时或保持活动的方法,因此我正在调查我们拥有的配置并创建了非常简单的 WCF 服务,并注意到 ReceiveTimeout 看起来永远不会执行。

我怀疑,主要问题是我们已经实现了自己的保持活动解决方案,但是如果有人使用 Telnet 从 Windows cmd 连接,它不执行我们的 ping 消息,它应该在指定的 ReceiveTimeout 后关闭连接(根据我的理解) - 如果我错了,请纠正我 - 我在 WCF 方面经验不多)

我们使用 CoreWcf.NetTcp,因为应用程序最初是在 .net-framework 中创建的。

出于演示目的,我创建了此服务:

[ServiceContract]
public interface ITestWcfService
{
    [OperationContract]
    string GetData(int value);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TestWcfService : ITestWcfService
{
    public TestWcfService() //only instantiated by WCF
    {
        Console.WriteLine("Constructor");
        OperationContext.Current.InstanceContext.Faulted += new EventHandler(Channel_Faulted);
        OperationContext.Current.InstanceContext.Closed += new EventHandler(Channel_Faulted);
    }

    private void Channel_Faulted(object sender, EventArgs e)
    {
        Console.WriteLine("Faulted");
    }

    public string GetData(int value)
    {
        Console.WriteLine("GetData");
        return $"{value}";
    }
}

还有这堂课

public static class MyTestHostClass
{
        public static string ServiceName => "WcfServiceName";

        private static WebApplication _app;

        public static void Open(int port)
        {
            var builder = WebApplication.CreateBuilder();
            builder.WebHost.UseNetTcp(port);
            builder.Services.AddServiceModelServices();

            _app = builder.Build();

            _app.UseServiceModel(serviceBuilder =>
            {
                serviceBuilder.AddService<TestWcfService>(options =>
                {
                });

                serviceBuilder.AddServiceEndpoint<TestWcfService, ITestWcfService>(GetTcpBinding(), $"net.tcp://0.0.0.0:{port}/{ServiceName}");
            });

            _app.StartAsync().Wait();
        }

        public static void Close()
        {
            if (_app != null)
            {
                _app.StopAsync().Wait();
                _app.DisposeAsync();
                _app = null;
            }
        }

        private static NetTcpBinding GetTcpBinding()
        {
            Console.WriteLine("Bindings");
            var binding = new NetTcpBinding(SecurityMode.Transport)
            {
                CloseTimeout = TimeSpan.FromSeconds(10),
                OpenTimeout = TimeSpan.FromSeconds(10),
                ReceiveTimeout = new TimeSpan(0, 0, 0, 10),
                SendTimeout = TimeSpan.FromSeconds(10)
            };

            return binding;
        }

    }

最后,我的控制台应用程序启动它:

Console.WriteLine("Hello, World!");

MyTestHostClass.Open(11999);
Console.WriteLine("WCF listening on port 11999");
await Task.Delay(Timeout.Infinite);

我可以看到消息

WCF is listening on port 11999
所以看起来一切顺利

然后我进入 Windows 中的 cmd 并运行 telnet 命令

telnet localhost 11999
- 它会连接但永远不会断开连接,即使它超过了 ReceiveTimeout。 我还在 WireShark 中检查了端口 11999 上没有任何活动,因此没有理由让它保持活动状态。 (我也没有看到来自 WCF 服务构造函数的控制台日志)

有什么想法需要设置以及为什么它不起作用?

编辑1:我尝试在简单的WinForms(net4.7.2)应用程序中托管相同的服务:

 public Form1()
 {
     InitializeComponent();

     host = new ServiceHost(typeof(TestWcfService));
     var binding = new NetTcpBinding()
     {
         CloseTimeout = TimeSpan.FromSeconds(10),
         OpenTimeout = TimeSpan.FromSeconds(10),
         ReceiveTimeout = new TimeSpan(0, 0, 0, 10),
         SendTimeout = TimeSpan.FromSeconds(10),
     };

     host.AddServiceEndpoint(typeof(ITestWcfService), binding, new Uri("net.tcp://localhost:11998/TestWcfService"));
     host.Open();

     Console.WriteLine("WCF Service listening on 11998");
 }

并且它超时就好了。 这是否意味着 CoreWCF 包中存在错误,或者我缺少 CoreWCF 中需要完成的某些部分?

编辑2: 为了进行测试,我在framework4.7.2和NET6中创建了服务。然后是framework4.7.2和NET6中的客户端。 两项服务的服务合同相同。

客户端实现看起来像这样(实际上在框架和NET6中是相同的,唯一的区别是对于NET6我必须安装System.ServiceModel.NetTcp nuget。


private ITestWcfService Client;
public Form1()
{
    InitializeComponent();

    var myBinding = new NetTcpBinding()
    {
        CloseTimeout = TimeSpan.FromSeconds(5),
        OpenTimeout = TimeSpan.FromSeconds(5),
        ReceiveTimeout = new TimeSpan(0, 0, 0, 5),
        SendTimeout = TimeSpan.FromSeconds(5)
    };
    var myEndpoint = new EndpointAddress("net.tcp://localhost:11998/TestWcfService");
    var myChannelFactory = new ChannelFactory<ITestWcfService>(myBinding, myEndpoint);
    try
    {
        Client = myChannelFactory.CreateChannel();
    }
    catch
    {
    }

}

private void button1_Click(object sender, EventArgs e)
{
    Client.GetData(5);
}

以下是行为总结: 框架4.7.2行为:

  • 服务器启动,客户端连接 - 没问题
  • 我将服务器超时设置为 10 秒。客户端超时时间为 5 秒。
  • 如果我在 10 秒内什么都不做,服务器就会超时并通知客户端
    • 客户端断开连接
    • 在Wireshark中可见

服务器端事件:

NET6 行为:

  • 服务器启动,客户端连接 - 没问题
  • 再次超时 - 服务器端 10 秒,客户端 5 秒
  • 如果我在 10 秒内不执行任何操作,我会看到服务器关闭连接,但没有任何内容发送到客户端,因此连接看起来处于活动状态,尽管事实并非如此。
    • 如果客户端尝试从服务调用某些内容,则无法访问该服务,因为连接已关闭并且在 5 秒内超时,无法访问。

但是没有任何内容发送到客户端,因此连接看起来仍在运行:

但是,如果我尝试再次从客户端调用方法,它就无法到达。 5秒后超时(客户端超时)

我们可以在服务器日志中看到它根本没有到达:

所以根据我的理解,CoreWCF 包中存在一个错误。

c# wcf tcp corewcf
1个回答
0
投票

如果有人发现这个问题并且遇到同样的问题,那么只需将 Nuget 包更新到新版本即可。此问题已在版本 1.5.2 及更高版本中修复。

© www.soinside.com 2019 - 2024. All rights reserved.