nitrous_007 Ответов: 1

Почему WCF callback бросает исключение (nettcpbinding)?


Привет,
У меня есть проблема с сбоем обратного вызова WCF после того, как обратный вызов работает нормально около 20 раз без каких-либо проблем. Обратный вызов завершается с ошибкой
<pre>The message could not be transferred within the allotted timeout of 00:00:20. There was no space available in the reliable channel's transfer window. The time allotted to this operation may have been a portion of a longer timeout.


Я собираюсь начать описывать свой код ниже. Пожалуйста, ознакомьтесь.

У меня есть контракт, как показано ниже.
  [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallBack1))]
    public interface IService1
    {
         [OperationContract(IsOneWay = true)]
         void StartSlot( int slotNumber);
      

    }

    [ServiceKnownType(typeof(Gen5.Model.STBTestModel))]
    public  interface ICallBack1
    {
         [OperationContract(IsOneWay = true )]
         void TestUpdateEvent(Gen5.Model.STBTestModel stb1);      
         [OperationContract(IsOneWay = true)]
         void UpdateLogBasic(int slot,string text,string testType);
         [OperationContract(IsOneWay = true)]
         void UpdateLogDetailed(int slot,string text,string testType);
         [OperationContract(IsOneWay = true)]
         void UpdateLogBasicandDetailed(int slot, string text, string testType);

     }

I create a proxy client using the code below. Please note the parameters for the proxy client. I also have the server defined further way below in code.

<pre> public class Proxy1
    {
          private EndpointAddress _endPointAddress;
          private NetTcpBinding _tcpBinding ;
          InstanceContext _mContext;
          System.ServiceModel.DuplexChannelFactory<IService1> proxy;
          IService1 proxyfunction;

          public Proxy1(InstanceContext context, string serviceName, string destIPAddresss, int portNumber,TimeSpan sendTimeOut,TimeSpan recieveTimeOut, TimeSpan openTimeOut, TimeSpan closeTimeOut)
          {
              _mContext = context;              
              _tcpBinding = new NetTcpBinding(SecurityMode.None, true);
              _tcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.None;
              _tcpBinding.ReliableSession.Ordered = true;
              _tcpBinding.ReliableSession.Enabled = true;
              _tcpBinding.ReliableSession.InactivityTimeout = new TimeSpan(24, 0, 0);
              _tcpBinding.Security.Mode = SecurityMode.None;
              _tcpBinding.OpenTimeout = openTimeOut;
              _tcpBinding.CloseTimeout = closeTimeOut;
              _tcpBinding.TransactionFlow = false;
              _tcpBinding.TransferMode = TransferMode.Buffered;
              _tcpBinding.SendTimeout = sendTimeOut;
              _tcpBinding.ReceiveTimeout = recieveTimeOut;           
              _tcpBinding.MaxConnections = 1000;
              _tcpBinding.ListenBacklog = 1000;
              _tcpBinding.MaxBufferSize = 1000000;//1MB
              _tcpBinding.MaxReceivedMessageSize = 1000000;//1MB
              _endPointAddress = new EndpointAddress("net.tcp://" +/*"10.248.1.3"*/destIPAddresss + ":" +portNumber.ToString() + "/" +"Service"/*serviceName.ToString()*/);
              proxy = new DuplexChannelFactory<IService1>(_mContext, _tcpBinding);
              proxyfunction = proxy.CreateChannel(_endPointAddress);
          }



Прокси-объект инициализируется в другом классе 'Controller' , который также является CallBackClass, как показано ниже. Этот класс 'Controller' реализует ' Gen5.WCF.ICallBack1'. Настройки таймаута, как показано ниже (конструктор показан выше): send-20 секунд, receive-24 часа, opentimeout=4 секунды, closetimeout=4 секунды. Клиент подключается к одной службе сервера и перезванивает тому же клиенту обратно. Так что это установка один к одному.

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
   public class Controller : Gen5.WCF.ICallBack1, Gen5.View.IController
   {

void CreateProxy(int slotNumber)
        {
            string ipTestPC = Shared.Functions.GetTestPCIP(slotNumber);
            proxy1 = new Gen5.WCF.Proxy1(new InstanceContext(this), "Service", ipTestPC, 4000, new TimeSpan(0, 0, 20),new TimeSpan(24, 0, 0), new TimeSpan(0, 0, 4), new TimeSpan(0, 0, 4));
        }



Это код подключения на стороне клиента для подключения к серверу. Я называю функцию запуска. Этот код выполняется на том же контроллере класса интерфейса обратного вызова.

proxy1[i].Connect();
proxy1[i].Start();


На стороне сервера Connect создает контекст обратного вызова в TestPCController, который реализует "IService1", а функция Start вызывает поток, который запускает тест пользовательского интерфейса. Это не блокирует, так как это поток. Пожалуйста, обратите внимание на все таймауты и настройки сервера в приведенном ниже коде, но я настроил его так же.

public partial class TestPCController : Gen5.WCF.IService1, ITestPCController
    {
        #region WCF
        ServiceHost host;
        InstanceContext context;
        NetTcpBinding binding1;
        ServiceThrottlingBehavior throttle;
        public delegate void Gen5TestPCLogUpdateEvent(object sender, int slot, string log, string testTitle, Shared.enumLogType logType);
        public static Gen5TestPCLogUpdateEvent TestPCLogUpdateEvent;
        static IGen5TestPCView viewTestPC;
        static STBTestModel stb;        
        static Devices devicesLocalTestPC;
        public TestPCController()
        {
        }
        public TestPCController(IGen5TestPCView viewGen5TestPC1)
        {
            viewTestPC = viewGen5TestPC1;
        }
        public void StartService(TimeSpan sendTimeOut, TimeSpan recieveTimeOut, TimeSpan openTimeOut, TimeSpan closeTimeOut)
        {

            string uri1 = "net.tcp://localhost" + ":4000/" + "Service";
            host = new ServiceHost(typeof(TestPCController), new Uri(uri1));
            context = new InstanceContext(this);
            binding1 = new NetTcpBinding(SecurityMode.None, true);
            binding1.Security.Message.ClientCredentialType = MessageCredentialType.None;
            binding1.ReliableSession.Ordered = true;
            binding1.ReliableSession.Enabled = true;
            binding1.ReliableSession.InactivityTimeout = new TimeSpan(24, 0, 0);
            binding1.SendTimeout = sendTimeOut;
            binding1.ReceiveTimeout = recieveTimeOut;
            binding1.OpenTimeout = openTimeOut;
            binding1.CloseTimeout = closeTimeOut;
            binding1.MaxBufferSize = 1000000;//1MB
            binding1.MaxReceivedMessageSize = 1000000;//1MB
            binding1.MaxConnections = 1000;
            binding1.ListenBacklog = 1000;
            host.AddServiceEndpoint(typeof(Gen5.WCF.IService1), binding1, "");


            throttle = host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
            host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
            if (throttle == null)
            {
                throttle = new ServiceThrottlingBehavior();
                throttle.MaxConcurrentCalls = 1000;
                throttle.MaxConcurrentSessions = 1000;
                throttle.MaxConcurrentInstances = 1000;
                host.Description.Behaviors.Add(throttle);
            }
            host.Open();
            Console.WriteLine("Started Gen5Service at " + uri1 + " successfully");


            STBTestModel.testUpdateEvent += STB_TestUpdateEvent;
            STBTestModel.logEvent += STB_LogEvent;
            STBTestModel.logActionEvent += STBTestModel_logActionEvent;

        }


public void Connect()
       {
           iServiceCallback = OperationContext.Current.GetCallbackChannel<Gen5.WCF.ICallBack1>();

       }

       public void StartSlot(int slotNumber)
       {

       }


С помощью обратного вызова вызываются около 4 различных функций. Они вызывают функции обратного вызова по крайней мере 50 раз подряд, а затем вылетают. Я знаю, что это не блокировка пользовательского интерфейса на клиенте, потому что функции обратного вызова не выполняют какой-либо код - он временно пуст - он все равно падает. Что-то в моем коде не так, что в какой-то момент вызывает сбой обратного вызова. Арендатор и т. Д. Понятия не имею, почему происходит сбой обратного вызова. Я знаю, что обратный вызов назначается только один раз - есть ли ограничение на то, сколько раз сервер может перезвонить, используя. Единственная странность, которую я заметил, - это то, что код всегда висит на одной и той же строке. Поскольку в коде обратного вызова на клиенте нет кода, я знаю, что это связано с WCF. Что-то вызывает тайм-аут обратного вызова, и это фиксированное событие.

Пожалуйста, поделитесь своими мыслями и не стесняйтесь задавать любые вопросы, пожалуйста. Я старался говорить как можно яснее.

Что я уже пробовал:

Я перепробовал все различные комбинации, такие как Concurrent.Muliple, Rentrant и т. д.

Я попытался сделать трассировку, но трассировка показывает только службу.Модель выбрасывает исключение и сбой.

Я удалил весь код из выполнения обратного вызова клиента, чтобы убедиться, что это не блок пользовательского интерфейса на стороне клиента.

Я добавил следующий код для привязки как на сервере, так и на клиенте

binding1.ReliableSession.Ordered = true;
          binding1.ReliableSession.Enabled = true;
          binding1.ReliableSession.InactivityTimeout = new TimeSpan(24, 0, 0);
          binding1.TransactionFlow = false;
          binding1.TransferMode = TransferMode.Buffered;


Я поставил контекст синхронизации = false

1 Ответов

Рейтинг:
8

nitrous_007

Ууууу. Решил проблему окончательно после 2 дней поиска неисправностей.

Я сделал следующее, чтобы исправить эти проблемы. Однако я не совсем уверен, какой шаг исправил эту проблему. Мне нужно было бы покопаться еще, чтобы найти это, но я хотел опубликовать это, пока не забыл.

1) у моего конструктора класса обратного вызова клиента не было конструктора по умолчанию.
как уже отмечалось здесь, это может вызвать проблемы.
WCF-повышение производительности с большим параллелизмом | theburningmonk.com[^]

2) я увеличил _tcpBinding.MaxConnections = 10000 и
_tcpBinding.ListenBacklog = 10000; на всякий случай.
Я увеличил также следующее:

_tcpBinding.MaxBufferSize = 100000000;//100MB
             _tcpBinding.MaxReceivedMessageSize = 10000000;//100MB


3) я реализовал синхронизацию ниже

[^]

4) я увеличил пул потоков как на клиенте, так и на сервере
Почему ответы WCF медленные, а SetMinThreads не работает? – Блог Дун Вэньлун [^]

5) я уже установил servertrace на север после того, как поместил нижеприведенные конфигурации в app.config сервера и клиента. Это всего лишь средство устранения неполадок, и теперь я могу подтвердить, что мои вызовы wcf и обратные вызовы занимают в среднем всего 4 мс(это клиент локального коммуникационного сервера). Я обработал более 500 обратных вызовов без каких-либо проблем. Я собираюсь поставить его в петлю на один день и посмотреть, что произойдет.

<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "c:\wcflog\traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
  <system.net>
    <defaultProxy>
      <proxy usesystemdefault="False"/>
    </defaultProxy>
  </system.net>
 
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>


Если у меня будут какие-то обновления, я опубликую их, но фью.