对Spray-can 启动http server的理解

来源:互联网 发布:win10无法磁盘优化 编辑:程序博客网 时间:2024/04/29 20:25

对IO(Http) ? Http.Bind(service, interface = “localhost”, port = 8080)的理解

先上代码,主启动程序及发送Http.Bind的类,放在文件Boo.scala中,与原官方的standalone例子相比,这个是稍微进行了修改。

package com.exampleimport akka.actor.{ActorRef, Actor, ActorSystem, Props}import akka.io.{Tcp, IO}import spray.can.Httpimport akka.pattern.askimport akka.util.Timeoutimport scala.concurrent.duration._object Boot extends App{  // we need an ActorSystem to host our application in  implicit val system = ActorSystem("on-spray-can")  // create and start our service actor  val service = system.actorOf(Props[MyServiceActor], "demo-service")  val server = system.actorOf(Props(new Server(service,system)), "demo-server")}class Server(service:ActorRef,implicit val  system:ActorSystem) extends Actor{  implicit val timeout = Timeout(5.seconds)  IO(Http) ! Http.Bind(service, interface = "localhost", port = 8088)  def receive = {    case x:Tcp.Bound => println("Tcp.Bound="+x)    case x => println("other messages : "+x)  }}

MyServiceActor这个类放在这里。

IO(Http)返回一个ActorRef变量,在spray.can.Http中实现,实际上源代码如下

    val manager = manager = system.actorOf(    props = Props(new HttpManager(Settings)) withDispatcher Settings.ManagerDispatcher,    name = "IO-HTTP")
  所以IO(Http)返回的就是这个manager。而这个manager就是在上面代码创建的HttpManager实例。

当这个manager接收到 Http.Bind消息时,就会根据Bind内容及配置创建一个实例去监听端口。代码在spray.can中实现HttpManager的部分。如下

case bind: Http.Bind =>      val commander = sender()      listeners :+= context.watch {        context.actorOf(          props = Props(newHttpListener(commander, bind, httpSettings)) withDispatcher ListenerDispatcher,          name = "listener-" + listenerCounter.next())      }

   这时HttpManager便启动了一个HttpListener实例去监听tcp端口,如果这个HttpListener实例成功绑定了tcp端口,则HttpListener会收到Tcp.Bound消息,这个Tcp.Bound消息也将会发送给上述代码中的server。注意这个Tcp.Bound消息在程序 整个运行过程中只会出现一次。除非你多次向IO(Http)发送Http.Bind消息。    此时HttpListener实例其实就是一直在监听tcp/ip层的数据, 当外部向服务器进行请求时,HttpListener实例首先会收到一个Tcp.Connected消息,然后马上创建HttpServerConnection实例,这个HttpServerConnection会将tcp层的消息封装成http层的消息。然后再发送给Http.Bind(service, interface = "localhost", port = 8080)中的service。这时service收到的消息其实已经是封闭好了的HttpRequest消息。      整个过程就是首先创建HttpManager,即IO(Http),然后向这个manager发送Http.Bind消息,创建HttpListener监听tcp层数据,一有外部连接,马上创建HttpServerConnection,该HttpServerConnection会将tcp层的数据进行封装,再以HttpRequest的形式传送给上层应用。

0 0
原创粉丝点击