Akka Streamsを利用してTCP通信ができる簡易なコードが書けることを知ったのでメモ。
詳しくは以下のページを参照。
package io.github.takayukiatkwsk.tcpclient import akka.actor.ActorSystem import akka.stream.scaladsl.{Flow, Keep, Sink, Source, Tcp} import akka.util.ByteString import scala.concurrent.Future class TcpClient(implicit val system: ActorSystem) { private val connection = Tcp().outgoingConnection("127.0.0.1", 8080) // 接続先のホストとポート private val mapFlow = Flow.fromFunction[ByteString, String](b => b.utf8String) private val sink = Sink.headOption[String] def send(body: String): Future[Option[String]] = { Source .single(ByteString(body)) // TCPサーバーに送るデータ(StringからByteStringに変換) .via(connection) .via(mapFlow) // サーバーから返却されたデータをStringに変換 .toMat(sink)(Keep.right) // 文字列を取り出す .run() } } object TcpClient extends App { implicit val actorSystem = ActorSystem("tcp-client") implicit val ec = actorSystem.dispatcher val tcpClient = new TcpClient() for { result <- tcpClient.send("Hello from TcpClient") } yield { println(result.getOrElse("Empty response")) } }
今回TCPサーバーはnc(netcat)コマンドを利用してちゃちゃっと確認できるようにしました。
### 8080ポートでListenして、hello, worldを返す $ echo -n 'hello world' | nc -l 8080
クライアントを実行してみます。
### ncコマンドとは別のターミナルで実行 $ sbt 'runMain io.github.takayukiatkwsk.tcpclient.TcpClient'
TCPサーバーに Hello from TcpClient というデータが送られてきて標準出力に出力されます。
$ echo -n 'hello world' | nc -l 8080 Hello from TcpClient
その後、TCPクライアントはTCPサーバーからの返信を受けて、ターミナルに hello world というデータが出力されます。
$ sbt 'runMain io.github.takayukiatkwsk.tcpclient.TcpClient' ... hello world
感想としては、Akka Streamsのみで比較的シンプルにソースコードを書くことができ、レスポンスの扱いもFuture値を使うことができるのでハンドリングしやすいなと思いました。リソースのオープン・クローズも隠蔽されていて使う側としては非常に楽だなあと感じます。選択肢の一つとして覚えておくと良さげですね。