Конференция ".Net" » Идентификация клиента в Remoting
 
  • simpson © (11.10.05 17:16) [0]
    Добрый день.
    Хочу определить, что именно i-й клиент вызывает сейчас метод remoting-объекта.

    Как реализовать сабж?
  • Lamer@fools.ua © (11.10.05 23:32) [1]
    >Как реализовать сабж?

    Хранить в remoting-объекте номер клиента?
  • DiamondShark © (12.10.05 09:25) [2]
    Простите, а в обчном объекте у вас не возникает желания узнать, кто его вызывает? А почему? А почему тут возникает?
  • Курдль © (13.10.05 11:22) [3]
    А как активируется Remoting-объект на сервере?
  • simpson © (13.10.05 12:35) [4]
    Есть сервис, выполняющий роль remoting-сервера. К нему могут подключаться клиенты как с других машин сети, так и с той же, на которой он работает.

    Требуется получить возможность в некоторых методах remoting-объекта определять, какой именно из клиентов этот метод вызвал. Нужен некий уникальный в пределах этого процесса (имеется ввиду сервис) идентификатор клиента.

    Это необходимо для реализации следующей штуки. Есть объект-синглтон:

    public class SingletoneSample : MarshalByRefObject, ISingletoneSample
    {
       public bool Lock()
       {
          // захватываем объект
          // здесь нужно определить, что за клиент вызывает этот метод
       }


       public bool UnLock()
       {
          // освобождаем объект
          // здесь тоже нужно определить, что за клиент вызывает этот метод
       }


       public void SomeAction()
       {
           // здесь выполняем какие-то действия
       }

    }



    Remoting-сервер создает этот синглтон. Очередной клиент, прежде, чем вызвать метод SomeAction, вызывает Lock. В методе Lock синглтон проверяет - если он не захвачен никем, то запоминает клиента по его идентификатору и переходит в состояние "захвачен". Если он уже в этом состоянии, то он возвращает false, и клиент не имеет права в этом случае вызывать SomeAction.

    Клиент, "захвативший" синглтон ранее, освобождает его с помощью UnLock.
    Т. е., нечто вроде распределенной критической секции, если уместна такая аналогия.


    public class ClientClass
    {
       void foo()
       {
           // получаем ссылку на синглтон через активатор
           ISingletoneSample sample = ...

           if (sample.Lock())
           {
                try
                {
                    sample.SomeAction();
                }

                finally
                {
                    sample.UnLock();
                }

           }
       }
    }



    > Курдль ©   (13.10.05 11:22) [3]
    См. комментарий с коде "получаем ссылку на синглтон через активатор". Т.е. Activator.GetObject

    > Lamer@fools.ua ©   (11.10.05 23:32) [1]
    Да я бы с радостью. Вопрос в том, где этот "номер" (точнее, идентификатор) взять? Что в качестве него использовать?

    Сразу оговорюсь, есть вариант, когда клиент "регистрируется" у синглтона (т. е. вызывает метод синглтона, который генерирует уникальный ID клиента). Потом этот ID передается в качестве доп. параметра всем методам синглтона.
    Но хотелось бы решение покрасивее. :)

    > DiamondShark ©   (12.10.05 09:25) [2]
    Потому что нужно организовать монопольный доступ к данным и ресурсам созданного синглтона. В случае с "обычным объектом" для этих целей используется критическая секция или любой другой объект синхронизации.

    В случае с remoting все сложнее. Даже в приведенном мной примере использования синглтона нет никакой гарантии, что последовательный вызов с клиента Lock, SomeAction и UnLock будет происходит в одном и том же трэде на сервере. А между Lock и UnLock в реальной жизни методов будет, мягко говоря, очень много, да и про времени процесс обращения к синглтону будет растянут.
  • Курдль © (13.10.05 12:42) [5]

    > См. комментарий с коде "получаем ссылку на синглтон через
    > активатор". Т.е. Activator.GetObject


    1. Для таких целей удобнее применять не синглтон (из welknown objects), а клиенски-активируемый объект. Тогда он принимает от клиента какие угодно параметры и живет с ними, пока не будет принудительно прибит, или не исчерпает срок аренды.

    2. Для синглтона на сервере можно получить инфу о клиенте, если передать ее в "контексте вызова" (CallContext)
  • simpson © (13.10.05 12:43) [6]
    > Курдль ©   (13.10.05 12:42) [5]
    1. CAO не подойдет по ряду причин.
    2. Вот это просьба рассмотреть подробнее.
  • Курдль © (13.10.05 12:54) [7]
    Для начала гляньте http://search.microsoft.com/search/results.aspx?qu=CallContext&View=ru-ru&st=b&c=4&s=5&swc=0
    а я покка поищу свои наработки. Но предупреждаю, легко не будет! :)
  • simpson © (13.10.05 12:57) [8]
    Спасибо. Буду читать.
  • Курдль © (13.10.05 13:06) [9]
    Класс, инкапсулирующий необходимые данные контекста вызова:

    using System;
    using System.Runtime.Remoting.Messaging;

    namespace CommonNameSpace
    {
    /// <summary>
    /// Summary description for CallContext.
    /// </summary>
    [Serializable]
    public class CallContextData: ILogicalThreadAffinative
    {
     private int clientID;
     private string login;

     public CallContextData(int AclientID, string ALogin)
     {
      clientID = AclientID;
      login = ALogin;
     }


     public int ClientID
     {
      get { return clientID; }

     }

     public string Login
     {
      get { return login; }

     }
    }
    }



    Удаленный объект:

    using System;
    using System.Runtime.Remoting.Messaging;

    namespace CommonNameSpace
    {
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class RemoteObject: MarshalByRefObject
    {
     public RemoteObject()
     {
      CallContextData ccd = (CallContextData)CallContext.GetData("CLIENT PARAMS");
      if (ccd != null)
       System.Console.WriteLine(String.Format("{0}
    \tСоздан удаленный объект с контекстом:\t{1}", DateTime.Now, ccd.Login));  
      else
       System.Console.WriteLine(String.Format("{0}\tСоздан удаленный объект", DateTime.Now));  
     }

     public string CheckCallContext()
     {
      CallContextData ccd = (CallContextData)CallContext.GetData("CLIENT PARAMS");
      System.Console.WriteLine(String.Format("{0}
    \tКонтекст вызова = \t{1}", DateTime.Now, ccd.Login));
      return ccd.Login;
     }
    }
    }



    Серверная консоль:

    using System;
    using System.Runtime.Remoting.Messaging;

    namespace CommonNameSpace
    {
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    public class RemoteObject: MarshalByRefObject
    {
     public RemoteObject()
     {
      CallContextData ccd = (CallContextData)CallContext.GetData("CLIENT PARAMS");
      if (ccd != null)
       System.Console.WriteLine(String.Format("{0}
    \tСоздан удаленный объект с контекстом:\t{1}", DateTime.Now, ccd.Login));  
      else
       System.Console.WriteLine(String.Format("{0}\tСоздан удаленный объект", DateTime.Now));  
     }

     public string CheckCallContext()
     {
      CallContextData ccd = (CallContextData)CallContext.GetData("CLIENT PARAMS");
      System.Console.WriteLine(String.Format("{0}
    \tКонтекст вызова = \t{1}", DateTime.Now, ccd.Login));
      return ccd.Login;
     }
    }
    }

  • Курдль © (13.10.05 13:08) [10]
    Скосячил, вот истинная серверная консоль:

    using System;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Tcp;

    namespace CommonNameSpace
    {
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
     /// <summary>
     /// The main entry point for the application.
     /// </summary>
     [STAThread]
     static void Main(string[] args)
     {
      TcpChannel channel = new TcpChannel(8008);
      ChannelServices.RegisterChannel(channel);
      System.Console.WriteLine(String.Format("{0}
    \tСоздан и зарегистрирован канал", DateTime.Now));

     
      RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject), "roURI", WellKnownObjectMode.SingleCall);

      System.Console.WriteLine("Press ENTER to exit");
      System.Console.ReadLine();
     }
    }
    }

  • DiamondShark © (13.10.05 14:20) [11]

    > Клиент, "захвативший" синглтон ранее, освобождает его с
    > помощью UnLock.
    > Т. е., нечто вроде распределенной критической секции, если
    > уместна такая аналогия.

    Уй, как замечательно.
    Вот я вызвал Lock, а потом у меня сетка рухнула.
    И что станет с сервером?

    Синглетон должен быть stateless.


    > В случае с "обычным объектом" для этих целей используется
    > критическая секция или любой другой объект синхронизации.


    Ну и сделайте client-activated объект. Пусть уже он пользуется стандартными механизмами синхронизации.
  • simpson © (13.10.05 14:59) [12]
    > Ну и сделайте client-activated объект
    См. simpson ©   (13.10.05 12:43) [6]

    > Вот я вызвал Lock, а потом у меня сетка рухнула.

    Это можно предусмотреть.

    > Синглетон должен быть stateless

    Не согласен.
  • DiamondShark © (13.10.05 19:09) [13]

    > > Ну и сделайте client-activated объект
    > См. simpson ©   (13.10.05 12:43) [6]

    Тема не раскрыта.


    > > Вот я вызвал Lock, а потом у меня сетка рухнула.
    > Это можно предусмотреть.

    Каким образом? Городить велосипед?
    А упавший cao подберёт life-time service.


    > > Синглетон должен быть stateless
    > Не согласен.

    Удачи.
  • newbusin (29.07.07 00:12) [14]
    Добрый день
    Мне очень нравится ваш форум,
    не мог бы кто нибудь разьеснить  последнее обсуждение,
    очень увлекательная тема)
    Заранее Спосибо
 
Конференция ".Net" » Идентификация клиента в Remoting
Есть новые Нет новых   [118639   +35][b:0][p:0.003]