none
【WCF】当服务端连接关闭后,但是客户端对象CommunicationState状态仍然是打开状态,为什么?(禁用可靠会话) RRS feed

  • 问题

  • 【WCF】当服务端连接关闭后,但是客户端对象CommunicationState状态仍然是打开状态,为什么?(禁用可靠会话)
    2019年6月21日 23:01

全部回复

  • 你好,

    通道的状态在服务端和客户端是不对称的,这意味着,即使服务端关闭了通道,但是客户端的通道侦听代理依然是开启状态,并且,如果服务端再次开启通道则依然可以正常通信。

    请参看下方的官方的文档。

    https://docs.microsoft.com/zh-cn/dotnet/framework/wcf/extending/client-channel-factories-and-channels

    Abraham

    2019年6月24日 8:17
  • 如果服务端再次开启通道则依然可以正常通信???
    2019年6月25日 7:13
  • 你好,

    是的,至少在我这边,非双工通信的模式下,在服务端关闭了情况下,重启服务端,客户端仍然可以正常调用服务端的服务。
    我这里写一个例子,你可以参看下。
    Server(Console application)

    class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost sh=new ServiceHost(typeof(MyService)))
                {
                    sh.Open();
                    Console.WriteLine("serivce is ready....");
                    Console.ReadLine();
                    sh.Close();
                }
    
            }
        }
        [ServiceContract]
        public interface IService
        {
            [OperationContract]
            string SayHello();
        }
        public class MyService : IService
        {
            public string SayHello()
            {
                return DateTime.Now.ToShortTimeString();
            }
    }
    


    Appconfig(Server).

        <system.serviceModel>
          <services>
            <service name="VM1.MyService" behaviorConfiguration="mybehavior">
              <endpoint address="" binding="basicHttpBinding" contract="VM1.IService"></endpoint>
              <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
              <host>
                <baseAddresses>
                  <add baseAddress="http://localhost:6300/"/>
                </baseAddresses>
              </host>
            </service>
          </services>
          <behaviors>
            <serviceBehaviors>
              <behavior name="mybehavior">
                <serviceMetadata/>
              </behavior>
            </serviceBehaviors>
          </behaviors>
        </system.serviceModel>
    


    Client(Console application,invoke the service by adding service reference).

            static void Main(string[] args)
            {
                ServiceReference2.ServiceClient client = new ServiceReference2.ServiceClient();
                Console.WriteLine(client.SayHello());
                Console.WriteLine(client.State);
    
    
                Console.WriteLine("请关闭服务端");
                Console.ReadLine();
                try
                {
                    Console.WriteLine(client.SayHello());
                }
                catch (Exception)
                {
                    Console.WriteLine("调用失败");
                }
                Console.WriteLine("请重启服务端");
                Console.ReadLine();
                Console.WriteLine(client.SayHello());
                Console.ReadLine();
            }
    


    客户端Appconfig(auto-generated),需要根据实际情况修改终结点为服务器地址,同一台机器上,Localhost就可以了。

        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BasicHttpBinding_IService1" />
                </basicHttpBinding>
            </bindings>
    
            <client>
                <endpoint address="http://10.157.13.69:6300/" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference2.IService"
                    name="BasicHttpBinding_IService1" />
            </client>
    </system.serviceModel>
    


    Abraham

    2019年6月26日 9:49
  • 谢谢你的回复 ,我们的场景有所不同,你用的是http协议短链接,我用的是net.tcp长链接,而且我这里客户端有一个长链接pool池的概念,会将已经建立的长链接,保存到在这个pool中,就像数据库的连接池类似一样。所以才会出现,当服务器端重启或链接被重置RST时,客户端pool中的链接状态还为打开状态,导致影响下一次业务通信。
    2019年6月26日 22:06
  • Hi,

    所以我并不认为官方文档所述有错,
    通道的状态在服务端和客户端是不对称的。
    你说的“影响影响下一次业务通信”,在我看来是会话服务,在每次通信的过程中,消息之间具有上下文关系(NetTcpBinding本身也支持会话模式)。如同下方配置

    [ServiceContract(SessionMode=SessionMode.Allowed)]
    Interface IDemo
    {
    Public void SayHello();
    }


    在这种情况下,我们可以显式地控制会话的开始与结束。

       [ServiceContract(SessionMode=SessionMode.Required)]
        interface IService
        {
            [OperationContract(IsOneWay=true,IsInitiating =true,IsTerminating =false)]
            void Start();
            [OperationContract(IsInitiating =false,IsTerminating =false)]
            int Add(int x);
            [OperationContract(IsOneWay = true,IsInitiating = false,IsTerminating =true)]
            void End();
    }


    Abraham


    2019年6月27日 2:07
  • 我们用的是percall模式,session会话模式我们不需要,不需要维护状态。

    我指的影响下一次通信,指的是链接池中的这个链接对象status还是opened打开状态,但实际上这条长链接已经断了。所以从pool中取出用时就,会出现 An existing connection was forcibly closed by the remote host ,从而影响业务调用。

    System.ServiceModel.CommunicationException: The socket connection was aborted. 
    This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:01:00'. ---> 
    System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host 
    at System.ServiceModel.Channels.SocketConnection.Write(Byte[] buffer, Int32 offset, Int32 size, Boolean immediate, TimeSpan timeout) 

    2019年6月27日 2:57
  • Hi,
    所以你在标题中所述,我已经贴出了官方文档的解释。
    通道的状态在服务端和客户端是不对称的。

    至于如何解决这个问题,“不影响你的业务”,我觉得我们应当考虑如何处理异常,如何处理你的业务逻辑。
    Abraham
    2019年6月27日 3:46