Akka TCP请求响应需要Thread.sleep

时间:2019-02-07 14:55:31

标签: scala tcp akka

早上好,我在使用TCP的基本akka IO时遇到问题

我具有akka文档中所示的客户端和服务器的基本实现:

Client is https://github.com/akka/akka/blob/v2.5.20/akka-docs/src/test/scala/docs/io/IODocSpec.scala#L67-L103

处理程序是[SimpleEchoHandler](https://github.com/akka/akka/blob/v2.5.20/akka-docs/src/test/scala/docs/io/EchoServer.scala#L227-L304),但另一个也以相同的方式起作用。

我有一个主要的测试方法,该方法会在首次连接到服务器时停止:

package core.september

import java.net.InetSocketAddress

import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props}
import akka.util.ByteString
import com.typesafe.config.ConfigFactory
import core.september.fastchain.network.Client

/**
 * @author ${user.name}
 */
object App {

  class ClientHandler extends Actor with ActorLogging {
    def receive = {
      case toLog ⇒ {
        log.debug("Client received "+ toLog.toString)
      }
        //Thread.sleep(200)
    }
  }


  def main(args : Array[String]) {
val config = ConfigFactory.parseString("akka.loglevel = DEBUG")
    implicit val system = ActorSystem("EchoServer", config)

var clientHand:ActorRef  = system.actorOf(Props(classOf[ClientHandler]))
var address:InetSocketAddress = new InetSocketAddress("localhost",5080)


var ackServer = system.actorOf(Props(classOf[EchoManager], classOf[SimpleEchoHandler],5080), "simple")
var client:ActorRef = system.actorOf(Props(classOf[Client],address,clientHand));

//Thread.sleep(200)

client ! ByteString("echo")

//Thread.sleep(200)

client ! "close"


  }

}

如果我在每条消息之后都没有注释掉两个Thread.sleep,则看不到已发送消息的输出,则没有睡眠的输出就是:

[DEBUG] [02/07/2019 15:47:21.812] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Attempting connection to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:47:21.816] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Connection established to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:47:21.825] [EchoServer-akka.actor.default-dispatcher-3] [akka://EchoServer/user/$a] Client received Connected(localhost/127.0.0.1:5080,/127.0.0.1:54616)

我完全松散了ByteString消息和“关闭”消息。 我的问题是为什么我需要将主线程置于睡眠状态以显示其他消息。 正确记录了thread.sleep消息:

[DEBUG] [02/07/2019 15:53:55.988] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Attempting connection to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:53:55.999] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/system/IO-TCP/selectors/$a/0] Connection established to [localhost/127.0.0.1:5080]
[DEBUG] [02/07/2019 15:53:56.011] [EchoServer-akka.actor.default-dispatcher-5] [akka://EchoServer/user/$a] Client received Connected(localhost/127.0.0.1:5080,/127.0.0.1:54712)
[DEBUG] [02/07/2019 15:53:56.157] [EchoServer-akka.actor.default-dispatcher-2] [akka://EchoServer/user/$a] Client received ByteString(101, 99, 104, 111)
[DEBUG] [02/07/2019 15:53:56.374] [EchoServer-akka.actor.default-dispatcher-4] [akka://EchoServer/user/$a] Client received connection closed

ClientActor实现是:

package core.september.fastchain.network

import akka.actor.{ Actor, ActorRef, Props }
import akka.io.{ IO, Tcp }
import akka.util.ByteString
import java.net.InetSocketAddress

object Client {
  def props(remote: InetSocketAddress, replies: ActorRef) =
    Props(classOf[Client], remote, replies)
}

class Client(remote: InetSocketAddress, listener: ActorRef) extends Actor {

  import Tcp._
  import context.system

  import akka.io.Tcp

  /*if (listener == null) {
   listener = Tcp.get(context.system).manager
  }*/

  IO(Tcp) ! Connect(remote)

  def  receive =  {
case CommandFailed(_: Connect) ⇒
  listener ! "connect failed"
      context stop self

case c @ Connected(remote, local) ⇒
  listener ! c
  val connection = sender()
  connection ! Register(self)
  context become {
    case data: ByteString ⇒
      connection ! Write(data)
    case CommandFailed(w: Write) ⇒
      // O/S buffer was full
      listener ! "write failed"
    case Received(data) ⇒
      listener ! data
    case "close" ⇒
      connection ! Close
    case _: ConnectionClosed ⇒
      listener ! "connection closed"
      context stop self
  }
  }
}

非常感谢。

1 个答案:

答案 0 :(得分:2)

您必须等待演员处理您的消息,然后退出应用程序。 最简单的方法是使用Akka的gracefulStop模式:

import akka.pattern.gracefulStop
client ! ByteString("echo")
client ! "close"
Await.result(gracefulStop(client, 1 second)(system)