Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package misc
- import java.net.InetSocketAddress
- import akka.actor.{ActorSystem, Props, Actor}
- import akka.io.{IO, Tcp}
- import akka.util.ByteString
- class Server extends Actor {
- import Tcp._
- import context.system
- IO(Tcp) ! Bind(self, new InetSocketAddress("localhost", 4321))
- def receive = {
- case b @ Bound(localAddress) =>
- // do some logging or setup ...
- case CommandFailed(_: Bind) => context stop self
- case c @ Connected(remote, local) =>
- val handler = context.actorOf(Props[SimplisticHandler])
- val connection = sender()
- connection ! Register(handler)
- }
- }
- object SimplisticHandler {
- object PacketByteString{
- /* метод возвращает Some(пакет, остаток), если есть пакет и None, если нет пакета */
- /* http://danielwestheide.com/blog/2012/11/21/the-neophytes-guide-to-scala-part-1-extractors.html */
- def unapply(bs: ByteString): Option[(ByteString, ByteString)] = {
- val (left, right) = (bs.takeWhile(_ != '_'), bs.dropWhile(_ != '_'))
- right match {
- case ByteString.empty => None
- case _ => Some(left, right.tail)
- }
- }
- }
- /* неявное преобразование ByteString в PacketByteString, чтобы можно было юзать метод наш unapply и паттерн матчить ByteString, отделяя пакеты */
- implicit class PacketByteString(b: ByteString) {
- def apply(b: ByteString) = new PacketByteString(b)
- }
- }
- class SimplisticHandler extends Actor {
- import Tcp._
- import SimplisticHandler._
- def receive = receiveBs(ByteString.empty) // инициируем пустой остаток
- def receiveBs(bs: ByteString): Receive = {
- case Received(data) => // получили данные
- /* функция рекурсивно отделяет пакеты и отпавляет их клиенту */
- def process: PartialFunction[ByteString, Unit] = {
- // юзаем наш метод unapply
- case PacketByteString(packet, rest) => // получилось отделить пакет
- sender() ! Write(packet) // отправляем его
- process(rest) // пробуем отделить еще один
- case rest => // не получилось отделить пакет
- context.become(receiveBs(rest)) // сохраняем остаток в области видимости новой функции receive и меняем поведение актора
- /* про context.become http://cs.nyu.edu/wies/teaching/ppc-14/material/lecture10.pdf */
- }
- process(bs.concat(data)) // склеиваем остаток от предыдущих пакетов и новые данные
- case PeerClosed =>
- context stop self
- }
- }
- object Run extends App {
- val actorSystem = ActorSystem("TcpServer")
- actorSystem.actorOf(Props[Server])
- }
Advertisement
Add Comment
Please, Sign In to add comment