繁体   English   中英

WCF-导致问题的聊天服务登录/注销

[英]WCF - Login/Logout of chat service causing issues

我在Windows服务中托管了WCF服务,但是客户端登录和注销时出现问题。

在客户端代码Login中,有时会出现以下异常。

Exception thrown: System.ServiceModel.FaultException 1 in System.ServiceModel.dll

Additional information: The operation 'RefreshClients' could not be completed because the sessionful channel timed out waiting to receive a message. To increase the timeout, either set the receiveTimeout property on the binding in your configuration file, or set the ReceiveTimeout property on the Binding directly.

我在绑定中已经收到了receiveTimeout="00:00:30"就像receiveTimeout="00:00:30" 但是上述例外几乎是即时的。 现在我不是专家,但这对我说超时之前还有30秒,但我的异常几乎立即发生。

客户端代码-登录

private DuplexChannelFactory<IMessageComs> remoteFactory;
private IMessageComs remoteProxy;
private Client clientUser;

public bool Login()
        {
            ConnectionStatus = "Logging in";

            IsConnecting = true;

            try
            {
                var ctx = new InstanceContext(CallBacks);
                remoteFactory = new DuplexChannelFactory<IMessageComs>(ctx, "NetTcpBinding_IMessageComs");
            }
            catch (Exception ex)
            {
                ConnectionStatus = "Remote Factory Error";
                IsConnecting = false;
                return false;
            }

            remoteFactory.Closed += remoteFactory_Closed;
            remoteFactory.Opening += remoteFactory_Opening;
            CallBacks.ClientsChanged += CallBacks_ClientsChanged;

            try
            {
                remoteProxy = remoteFactory.CreateChannel();                 
            }
            catch (Exception ex)
            {
                ConnectionStatus = "Remote Proxy Error";
                IsConnecting = false;
                Console.WriteLine(ex.Message);
                return false;
            }

            try
            {
                clientUser = remoteProxy.ClientConnect(Environment.UserName.ToUpper()); << Exception Happens Here
            }
            catch (Exception ex)
            {
                IsConnecting = false;
                Console.WriteLine(ex.Message);
                return false;
            }

            if (clientUser != null)
            {
                ConnectionStatus = "Online";
                IsConnecting = false;
                LoggedIn = true;
                remoteFactory.Faulted += remoteFactory_Faulted;

                // Now get the online user list
                var users = remoteProxy.GetClientsAsync();

                var connectedUser = users.Result;

                if (connectedUser != null)
                {
                    foreach (Client c in connectedUser)
                        OnlineUsers.Add(c);
                }
            }
            else
            {
                IsConnecting = false;
                ConnectionStatus = "Offline";
                return false;
            }

            return true;
        }

服务器端代码

public Client ClientConnect(string userName)
    {
        AddEvent(userName + " is attempting to connect");

        var exists = Clients.Where(x => x.Client.UserName == userName);

        if (exists.Count() == 0)
        {
            Client c = new Client();
            c.UserName = userName;
            var tmpNo = c.ID;   // Force ID generation?
            c.SessionID = OperationContext.Current.Channel.SessionId;

            ServerClient sc = new ServerClient(c, CurrentCallback);

            OperationContext.Current.Channel.Faulted += Channel_Faulted;

            Clients.Add(sc);

            AddEvent(userName + " now connected and clients being notified");

            if (Clients.Count > 0)
            {
                // Get clients list
                var Clientlist = new List<Client>();

                foreach (ServerClient s in Clients)
                {
                    Clientlist.Add(s.Client);
                }

                foreach (ServerClient s in Clients)
                {
                    s.CallBack.RefreshClients(Clientlist);
                }
            }               

            return c;
        }
        else
        {
            AddEvent(userName + " is already connected");
            return exists.First().Client;
        }
    }

编辑1:堆栈跟踪

at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)

异常详细信息堆栈跟踪-服务器堆栈跟踪:

   at System.ServiceModel.Channels.ServiceChannel.ThrowIfIdleAborted(ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at EMS.Messaging.Service.IMessageComsCallBack.RefreshClients(List`1 clients)
   at EMS.Messaging.Service.ComsService.ClientConnect(String userName)
   at SyncInvokeClientConnect(Object , Object[] , Object[] )
   at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

编辑2:服务器配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
  </startup>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="EMS.Messaging.Service.ComsService" behaviorConfiguration="MessagingServiceBehaviour">
        <endpoint address="" binding="netTcpBinding" contract="EMS.Messaging.Service.IMessageComs" bindingConfiguration="tcpBinding"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://SERVERNAME:8000/MessagingService/service" />
            <add baseAddress="net.tcp://SERVERNAME:8001/MessagingService/service" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MessagingServiceBehaviour">
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceThrottling maxConcurrentSessions="100"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="tcpBinding" maxBufferSize="67108864" maxReceivedMessageSize="67108864" maxBufferPoolSize="67108864" transferMode="Buffered" closeTimeout="00:00:10"
                         openTimeout="00:00:10" receiveTimeout="00:20:00" sendTimeout="00:01:00" maxConnections="100" portSharingEnabled="true">
          <security mode="None"/>
          <readerQuotas maxArrayLength="67108864" maxBytesPerRead="67108864" maxStringContentLength="67108864" />
          <reliableSession enabled="true" inactivityTimeout="00:20:00" />
        </binding>
      </netTcpBinding>
      <customBinding>
        <binding name="mexBinding">
          <tcpTransport maxPendingConnections="100">
            <connectionPoolSettings groupName="default" maxOutboundConnectionsPerEndpoint="100"/>
          </tcpTransport>
        </binding>
      </customBinding>
    </bindings>
  </system.serviceModel>
</configuration>

问题出在服务器上您的客户端集合中的客户端之一。 在先前连接的客户端之一上,当他们调用其回调方法RefreshClients时,会引发异常。 由于未捕获并处理此错误,因此将其返回给名为ClientConnect的客户端。 注册有故障的回调以将其从Clients集合中删除是不够的,有两个原因。 首先,当您遍历Clients集合时,您可能会遇到竞争状态,在这种情况下会进入故障状态。 此外,直到您尝试拨打电话时,才会发现某些故障模式。 您需要将回调包装在try / catch块中。 您也有其他潜在问题。 如果客户端也几乎同时调用ClienConnect,则当clientB调用Clients.Add时,可以在foreach块中让clientA的调用在Client上迭代。 这将导致迭代在基础集合被修改时引发异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM