Thursday, May 14, 2009

A Simple Server in Scala

Surprisingly enough there isn't much information regarding using sockets, scala and actors together. I figured that something like this would be quite wide spread however I found it straight forward to create. I took my knowledge of actors and then followed some sample code for Java sockets.

Right now all the server does is listen for connections and print out what clients send to it, nothing special. There are some downsides to the way I'm doing things. The actor class by default spawns it's own thread which can get ugly fast however it is easy enough to convert over to coroutine like behavior. The reason I haven't done this yet is because I'm not using select to see if there is data so waiting for one receive or in this case line would block the whole thread and that wouldn't be nice. Anyways here is my code.


  1. package stdServer
  2.  
  3. import java.io._
  4. import java.net.{InetAddress,ServerSocket,Socket,SocketException}
  5. import scala.actors.Actor
  6. import scala.actors.Actor._
  7.  
  8.  
  9. object Server
  10. {
  11.   def main(args : Array[String])
  12.   {
  13.     val port = 6669
  14.    
  15.     try
  16.     {
  17.         val listener = new ServerSocket(port)
  18.         var numClients = 1
  19.  
  20.         println("Listening on port " + port)
  21.        
  22.         while (true)
  23.         {
  24.             new ClientHandler(listener.accept(), numClients).start()
  25.             numClients += 1
  26.         }
  27.  
  28.         listener.close()
  29.     }
  30.     catch
  31.     {
  32.         case e: IOException =>
  33.             System.err.println("Could not listen on port: " + port + ".")
  34.             System.exit(-1)
  35.     }
  36.  
  37.   }
  38.  
  39. }
  40.  
  41.  
  42. class ClientHandler(socket : Socket, clientId : Int) extends Actor
  43. {
  44.   def act
  45.   {
  46.     try
  47.     {
  48.         val out = new PrintWriter(socket.getOutputStream(), true)
  49.         val in = new BufferedReader( new InputStreamReader(socket.getInputStream()))
  50.      
  51.         print("Client connected from " + socket.getInetAddress() + ":" + socket.getPort)
  52.         println(" assigning id " + clientId)
  53.      
  54.         var inputLine = in.readLine()
  55.         while (inputLine != null)
  56.         {  
  57.             println(clientId + ") " + inputLine)
  58.        
  59.             inputLine = in.readLine()
  60.         }
  61.  
  62.         socket.close()
  63.      
  64.         println("Client " + clientId + " quit")
  65.     }
  66.     catch
  67.     {
  68.         case e: SocketException =>
  69.             System.err.println(e)
  70.      
  71.         case e: IOException =>
  72.             System.err.println(e.printStackTrace())
  73.          
  74.         case e =>
  75.             System.err.println("Unknown error " + e)
  76.     }
  77.   }
  78. }
  79.  
  80.  


One of things I like about this code is that it shows off mixing Java code with Scala. If you haven't noticed it fits right in and you can't really tell that there is Java embedded.


I also wrote a version of this code with Scala's remote actors however it seems limiting. When I tried to connect to telnet and typed something my server instantly crashed with an out of memory error. I'm guessing that remote actors only can only talk to each other which means that I would have to learn the protocol that it is using and mimic it in my client thats not written in Scala and then hope no one tried to use telnet on it. I'd rather just use normal TCP/IP sockets and know that it will work with pretty much anything.

Well thats it for now, next time I hope to have an non-blocking version of this code with concurrent actors and perhaps some basic functionality.

1 comment:

  1. Hi,

    great post first of all. Actors though don't seem to be used in the Actor way. Their basic benefit is async message sharing and a big number of them available. Seams more that you have used them as a normal thread.

    ReplyDelete