Blogaomu

WEBアプリケーション開発とその周辺のメモをゆるふわに書いていきます。

Akka Streamsを利用するTCPクライアントのメモ

Akka Streamsを利用してTCP通信ができる簡易なコードが書けることを知ったのでメモ。

詳しくは以下のページを参照。

doc.akka.io

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値を使うことができるのでハンドリングしやすいなと思いました。リソースのオープン・クローズも隠蔽されていて使う側としては非常に楽だなあと感じます。選択肢の一つとして覚えておくと良さげですね。