2016-03-30 2 views
2

Я использую Java Play Framework. Я использую веб-сокеты для взаимодействия клиентского сервера. На стороне сервера у нас есть актеры, которые отвечают на запрос клиента. Проблема, с которой я столкнулся: Я хочу, чтобы, когда клиент открывает соединение с веб-сокетом с актером Hakka на сервере, он фактически открывает пул для этого актера, а затем мне нужно проследить путь клиента-актера для этого экземпляра , так что всякий раз, когда какое-то другое действие происходит в каком-то другом классе, этот класс информирует этого актера (используя путь экземпляра, который был прослежен), что действие произошло, и затем этот актер сообщает пользователю (клиенту), что это действие произошло. Я на самом деле с помощьюAkka Actor Path для этого примера

String ClientPushActorPath = akka.serialization.Serialization.serializedActorPath(self()); 

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

PushCacheManager cache = PushCacheManager.getInstance(); 
cache.load(qiid); 
String ActorPath = cache.get("ClientPushActorPath"); 
ActorSelection ClientPushActor = system.actorSelection(ActorPath); 
ClientPushActor.tell(m4, getSelf()); 

Так код выше просто говорит, что первый я пойти и получить шотландцы пути из кэша (он кэшируется в памяти для дальнейшего использования) и затем я пытаюсь передать этот путь для выбора актера. Когда я получаю объект для выбора актера, я использую это, чтобы сообщить другому игроку сообщение, которое мне нужно передать, которое является m4. Пожалуйста, исправьте меня, когда я ошибаюсь. Я не могу видеть актера, используя этот путь. Я чувствую, что я отслеживаю путь неправильно. Пожалуйста, исправьте меня. Than

+0

Почему вы беспокоитесь о 'ActorPath'? Что мешает вам просто хранить «ActorRef» где-то и использовать его для отправки ответа?Использование 'ActorRef' * - это идиоматический способ сделать это в Akka – Anton

+0

Возможно ли сохранить ссылку актера для этого конкретного экземпляра клиента? Прошу прощения, я новичок в акке. – yukzz

+0

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

ответ

2

Пожалуйста, имейте это в виду, это займет некоторое время, чтобы пройти через это, но оно должно дать вам хорошее представление о том, что делать. Примечание. Я предполагаю, что вы все еще используете Play 2.4.x и еще не обновили Play 2.5.x. А также, что вы используете Java (хотя, если вы можете переключиться, я бы рекомендовал API Akka Scala).


Шаг 1: определение актера, обрабатывающая подключение WebSocket

В контроллере можно было бы написать так:

public static WebSocket<String> socket() { 
    return WebSocket.withActor(MyWebSocketActor::props); 
} 

Это означает, что каждое соединение WebSocket будет обрабатываться актерский экземпляр типа MyWebSocketActor. Затем вы должны реализовать актера, как это:

import akka.actor.*; 

public class MyWebSocketActor extends UntypedActor { 

    public static Props props(ActorRef out) { 
     return Props.create(MyWebSocketActor.class, out); 
    } 

    private final ActorRef out; 

    public MyWebSocketActor(ActorRef out) { 
     this.out = out; 
    } 

    public void onReceive(Object message) throws Exception { 
     if (message instanceof String) { 
      out.tell("I received your message: " + message, self()); 
     } 
    } 
} 

Параметр ActorRef out, что вы видите на самом деле основной актер (генерируется из игры). Вам не нужно ничего с этим делать, просто помните, что как только вы отправите что-то этому актеру out, он обработает его клиенту.

Вы также должны определить правильный путь в файле routes:

GET /ws controllers.Application.socket()

Шаг 2: определение того, как управлять всеми WebSocket актеров

В целом у вас есть два варианта - либо вы «смотрите вверх» созданных выше субъектов, либо предоставляете какой-то механизм их управления (вид реестра)

  • Шаг 2.1: глядя вверх WebSocket актеров

    Преимущество здесь в том, что вам не нужен дополнительный реестр/менеджер или аналогичный. Недостатком является то, что действительно сложно понять, какой актер служит для подключения к WebSocket.

    Вы бы использовать actorSelection для этого:

    system.actorSelection("system/websockets/*/handler");

    Это работает, потому что, как я уже говорил ранее, есть подключение актеров обработчика порождаемые Play - так их адреса, как это: akka://application/system/websockets/42/handler. Опять же, таким образом вы можете получить всех актеров, но не одиноких (потому что вы не знаете их номер обработчика).

  • Шаг 2b: управление WebSocket актеры Преимущество здесь в том, что вы можете полностью управлять актерами и назначить различную информацию для них. Недостаток заключается в том, что у вас есть еще один актер, чтобы заботиться о (хотя на самом деле не проблема, Akka довольно хорошо на этом)

Вы бы создать новый актер, как:

public class ManagerActor extends UntypedActor { 

    List<ActorRef> slaves; 

    public MyWebSocketActor() { 
     this.slaves = new ArrayList<>(); 
    } 

    public void onReceive(Object message) throws Exception { 
     if (message instanceof RegisterMe) { 
      // a new WebSocket was created so we can register him 
      slaves.add(sender()); 

      // also register a DeathWatch so that we know when the WebSocket actor dies 
      context.watch(sender()); 
     } else if (message instanceof Terminated) { 
      // remove from the list 
      ... 
     } 
    } 
} 

Шаг 3: все вместе

Теперь, помните нашего актера WebSocket сверху? Ему нужно как-то зарегистрироваться у Менеджера. Опять же, вы можете сделать это двумя способами: вы можете «найти» менеджера с помощью context.system.actorSelection("user/manager"), или если у вас уже есть ссылка (ActorRef) менеджеру, вы можете указать ее как параметр конструктора при создании актера WebSocket

вы могли бы использовать preStart метод, который доступен для каждого актера и сделать вашу регистрацию:

public class MyWebSocketActor extends UntypedActor { 

    .... 

    @Override 
    public void preStart() throws Exception { 
     context().system().actorSelection("user/manager").tell(RegisterMe, self()); 
     super.preStart(); 
    } 
} 

Теперь, когда у вас есть все WebSocket актеров, которыми управляет ... Диспетчер, вы можете определить новые сообщения, которые он может обработать, и сказать ему, что он должен направить m4 на клиентов. Обратите внимание, что внутри Менеджера можно использовать что-то вроде Map, где ActorRef - это ключ, а значение - какое-то свойство пользователя или все, что вы хотите.

Смежные вопросы