使用websockets在客户端和服务器之间进行私有通信



我是scala的新手,无法使用websocket向客户端发送私有消息。

这是我的控制器:

object Client extends Controller {
  def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
    out => ClientWebSocket.props(uuid)
  }
 // Test Method to send message to websocket connected client
  def sendMessage(guid: String) = Action { implicit request =>
    val system = ActorSystem("default")
    val out = system.actorOf(Props(classOf[ClientWebSocket], guid))
    out ! SendUpdate("Message Recieved")
    Ok
  }
}

这是我的演员课:

object ClientWebSocket {
  def props(uuid: String) = Props(new ClientWebSocket(uuid))
  case class SendUpdate(msg:String)
}
class ClientWebSocket(uuid: String) extends Actor {
  import ClientWebSocket._
  def receive = {
    case SendUpdate(msg:String) =>
      sender ! "Message is " + msg
  }
}

当我用客户端的uuid调用sendMessage时,我收到了akka死信遇到的错误。非常感谢您的帮助。

首先,在WebSocket方法中,您需要使用提供的ActorRef而不是sendersender可能是层次结构中的其他东西。

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  import ClientWebSocket._
  def receive = {
    case SendUpdate(msg: String) =>
      out ! s"Message is $msg"
  }
}

其次,你在sendMessage中收到了死信,因为你正在回复你的控制器,不幸的是,控制器不是Actor。

问题是您无法获得ActorRef,并且由于您不知道参与者的名称,因此无法使用ActorSelection。因此,你需要对自己的应用程序进行WebSocket调用,从web浏览器/JavaScript调用它,或者进行一些黑客攻击以找到参与者。

编辑

您的ClientWebSocket可以向另一个参与者注册(例如,在preStart中通过ActorSelection或通过ActorRef作为道具参数),该参与者保留对所有websocket的Map[String, ActorRef]引用,然后使用死亡监视来监视它们。然后,该actor会将您的SendUpdate转发给正确的websocket actor。由于只能在acceptWithActor中返回Props,因此无法形成真正的层次结构。

out参数是ActorRef,您将使用它向客户端发送消息,因此您需要将其保留在Actor中。

object Client extends Controller {
  def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
    // out is an actor to what the outbound messages should go to respond to remote client
    out => ClientWebSocket.props(uuid, out)
  }
}

您的ClientWebSocket参与者如下:

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor ...

伴随物体如下

object ClientWebSocket {
  def props(uuid: String, out: ActorRef) = Props(classOf[ClientWebSocket], uuid, out)
}

在ClientWenSocket中,您可以使用CentralWebSocketControl Actor将Actor注册/注销为:

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  @throws[Exception](classOf[Exception])
  override def preStart(): Unit = {
    super.preStart()
    CentralWebSocketControl.instance ! RegisterMe(uuid)
  }
  @throws[Exception](classOf[Exception])
  override def postStop(): Unit = {
    CentralWebSocketControl.instance ! UnregisterMe(uuid)
    super.postStop()
  }
}

CentralWebSocketControl Actor可以是:

class CentralWebSocketControl extends Actor {
  val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()
  override def receive: Actor.Receive = {
    case RegisterMe(uuid) =>
      clientActors += uuid -> sender()
    case UnregisterMe(uuid) =>
      clientActors -= uuid    
  }
}
object CentralWebSocketControl {
  val instance = Akka.system.actorOf(Props(classOf[CentralWebSocketControl]), name = "CentralWebSocketControl")
} 

要将消息发送到由uuid标识的给定ClientWebSocket,您可以向CentralWebSocketControl发送消息,后者可以将消息委托给已注册的ClientWebSocket。

class CentralWebSocketControl extends Actor {
  val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()
  override def receive: Actor.Receive = {
    ...    
    case SendUpdateTo(uuid: String, msg: String) =>
      clientActors.get(uuid) match {
        case Some(actor) =>
          actor ! SendUpdate(msg)
        case None =>
          ???
      }
  }
}

最后是

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  override def receive: Receive = {
    case SendUpdate(msg) =>
      out ! msg
  }
  ...    
}

相关内容

  • 没有找到相关文章

最新更新