( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

はてなスーパーPre記法がScalaに対応したらしいのでEchoServerのソース貼ってみる

はてなスーパーPre記法がScalaに対応したらしいのでEchoServerのソース貼ってみます。
いちおう、Scala hack-a-thonの資料にも反映済み。


yuroyoro/scala-hackathon · GitHub
Dropbox - 404


普通のServerSocket版と、NIOノンブロッキングチャネル版の2種類書いてみましたが、ヒドいソースなんで添削希望ですだれかボスケテ


ServerSocket版

import scala.actors.Actor
import scala.actors.Actor._

import java.io._
import java.net.{ServerSocket, Socket }

object EchoServer{

  def main( args:Array[String] ) = {
    EchoActor.start()
    EchoActor ! Start( args.first.toInt )
  }
}

case class Start( port:Int )
case class Wait( serverSocket:ServerSocket )
case class Accept( socket:Socket )

object EchoActor extends Actor {

  def act() = {
    loop{
      react {
        case Start( port ) => {
          val serverSocket = new ServerSocket( port )
          println( "EchoServeが起動しました。port=%d".format( port ) )
          EchoActor ! Wait( serverSocket )
        }
        case Wait( serverSocket ) => {
          val socket = serverSocket.accept
          val acceptActor = new AcceptActor
          acceptActor.start()
          acceptActor! Accept( socket )
          EchoActor ! Wait( serverSocket )
        }
      }
    }
  }
}

class AcceptActor extends Actor {
  def act() = {
    react {
      case Accept( socket ) => {
        val address = socket.getInetAddress
        println( address + ":[接続しました]" )

        val in = new BufferedReader( new InputStreamReader(socket.getInputStream ) )
        val out = new PrintWriter( socket.getOutputStream,  true)
        val s = in.readLine
        println( "%s:%s".format( address , s ) )
        out.println( s )

        out.close
        in.close
        socket.close
        println( address + ":[切断しました]" )
      }
    }
  }
}

NIO ノンブロッキングチャネル版

import scala.actors.Actor
import scala.actors.Actor._
import scala.collection.jcl.Conversions._

import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.{ SelectionKey,
  Selector, ServerSocketChannel, SocketChannel }
import java.nio.charset.Charset

object EchoServerNIO{

  def main( args:Array[String] ){
    EchoActor.start()
    EchoActor ! Start( args.first.toInt )
  }
}

case class Select()
case class Start( port:Int )
case class Accept( key:SelectionKey )
case class Read( key:SelectionKey )

object EchoActor extends Actor {
  val BUF_SIZE = 1024
  lazy val selector = Selector.open
  lazy val serverChannel = ServerSocketChannel.open

  def act() = {
    loop {
      react {
        case Start( port ) => {
          serverChannel.configureBlocking(false)
          serverChannel.socket.bind( new InetSocketAddress( port ) )
          serverChannel.register(selector, SelectionKey.OP_ACCEPT )

          println( "EchoServeが起動しました。port=%d".format( port ) )
          EchoActor ! Select
        }
        case Select => {
          selector.select
          selector.selectedKeys.foreach{ key =>
            if( key.isAcceptable ){
              EchoActor ! Accept( key )
            }
            else if( key.isReadable ){
              EchoActor ! Read( key )
            }
          }
          EchoActor ! Select
        }
        case Accept( key ) => {
          val socket = key.channel.asInstanceOf[ServerSocketChannel]
          socket.accept match {
            case null =>
            case channel => {
              val remoteAddress = channel.socket.getRemoteSocketAddress.toString();
              println(remoteAddress + ":[接続しました]" )

              channel.configureBlocking(false)
              channel.register(selector, SelectionKey.OP_READ);
            }
          }
        }
        case Read( key ) => {
          val channel = key.channel.asInstanceOf[SocketChannel]
          val buf = ByteBuffer.allocate(BUF_SIZE)
          val charset = Charset.forName("UTF-8")

          val remoteAddress = channel.socket.getRemoteSocketAddress.toString();
          def close = {
            channel.close()
            println( remoteAddress + ":[切断しました]" )
          }

          channel.read( buf ) match {
            case -1 => close
            case 0 =>
            case x => {
              buf.flip
              println( "%s:%s".format( remoteAddress, charset.decode(buf).toString ))
              buf.flip
              channel.write( buf )
              close
            }
          }

        }
      }
    }
  }
}