Как отправлять сообщения между удаленными участниками Akka?

#scala #networking #messaging #actor #akka

#scala #сеть #обмен сообщениями #актер #akka

Вопрос:

Я хочу создать очень простое приложение для чата, которое должно работать без какого-либо центрального сервера с использованием удаленных участников Akka.

Я в основном хочу запустить один экземпляр приложения с IP-адресом A. Затем я хочу запустить экземпляр приложения с IP-адресом A и сообщить ему, что удаленный экземпляр находится по IP-адресу B.

Как бы я это настроил? Документация Akka обычно охватывает только варианты использования клиент / сервер, и даже базовые вещи оставили меня в полном замешательстве, например, где использовать Actor.actorOf vs Actor.register Actor.remote . vs .

В настоящее время мой код выглядит так:

 import collection.mutable.{ArrayBuffer, HashSet}
import akka.actor.Actor

sealed trait Event    
/** Join tells the peer that there is a new peer and 
  * requests a list of known peers and messages. */
case class Join(user: String, ipAddress: String) extends Event
/** Join tells the peer that there is a new peer. */
case class Register(user: String, ipAddress: String) extends Event
case class Leave(user: String, ipAddress: String) extends Event    
case object GetChatLog extends Event
case object GetPeers extends Event
case class ChatLog(log: Seq[Message]) extends Event
case class Peers(peers: Seq[Peer]) extends Event
case class Message(sender: String, time: Long, message: String) extends Event

class ChatPeer(val name: String, ipAddress: String) extends Actor {
  val chat = Actor.remote.actorFor("chat:service", ipAddress, 2552) //This is not what I want...
  val messages = ArrayBuffer[Message]()
  val peers = HashSet[Peer]()

  def join = {
    (chat ? Join(name, ipAddress)).as[(Seq[Peer], Seq[Message])]
  }

  def register = chat ! Register(name, ipAddress)

  def leave = chat ! Leave(name, ipAddress)

  def send(message: String) = {
    val msg = Message(name, System.currentTimeMillis(), message)
    messages  = msg
    chat ! msg
  }

  def getMessages = (chat ? GetChatLog).as[ChatLog]
    .getOrElse(throw new Exception("Couldn't get the chat log from ChatServer"))

  def getPeers = (chat ? GetPeers).as[Peers]
    .getOrElse(throw new Exception("Couldn't get the peers from ChatServer"))


  def receive = {
    case msg@Message(from, time, message) =>
      println(msg)
      messages  = msg

    case GetChatLog =>
      self reply messages

    case GetPeers =>
      self reply peers

    case Join =>
      peers  = Peer(name, ipAddress)
      self reply ((peers, messages))

    case Register(user, ipAddress) =>
      peers  = Peer(user, ipAddress)

    case Leave(user, ipAddress) =>
      peers -= Peer(user, ipAddress)

  }
}

case class Peer(name: String, ipAddress: String)
  

Комментарии:

1. «Сервер» — это любой участник, который доступен удаленно. «Клиент» — это любой участник, который ищет другого участника на удаленном хосте. Фактически, кластер Akka — это не клиент / сервер, а сервер и клиент / сервер и клиент.

Ответ №1:

Не уверен, что я понимаю, чего вы хотите от вашего примера кода.

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

 remote.start("localhost", somePort).register("chat-main", actorOf[ChatMain])
  

а затем попытайтесь подключиться к серверу другого узла

 val otherActor = remote.actorFor("chat-main", otherHost, somePeer)
  

По сути, вам нужно будет одновременно создавать сервер и клиент своих одноранговых узлов. Оставшаяся часть настройки — это логика согласования и чата, но технически это не намного сложнее, чем этот простой пример на веб-сайте Akka.