Some weeks ago I attended JavaOne (a pretty neat conference, even for non-Java-heads like me) and got in touch with several non-Java languages running on the JVM (nothing really new next to Project Fortress, but I never got into most for real).
Since I wanted to learn some language not resembling any other I already know (even a little), I decided some hours ago to start digging into Clojure, which is a LISP dialect running on the JVM using STM (Software Transactional Memory) and created with concurrency in mind. Check the website for more information.
After some hacking I got a first ‘application’ running. Since recently there’s been some little meme at work regarding echo servers, I decided to write a very basic line-oriented echo server in Clojure.
The result is a server using one thread per connection which just sends back lines to a connected client as-is. Nothing fancy, but might be a useful start for developing basic network applications using Clojure.
Enjoy!
; Some imports we need | |
(import '(java.net ServerSocket Socket SocketException) | |
'(java.io InputStreamReader BufferedReader OutputStreamWriter) | |
) | |
; Helper to run a callable in a new thread | |
(defn threaded [fun] | |
; Create a new thread | |
(let [thread (new Thread fun)] | |
; And start it | |
(. thread (start)) | |
) | |
) | |
; Accept function: whenever a new connection is made to the listening socket, | |
; this function spawns of a new thread running the connection handler function, | |
; providing the input- and output-stream | |
(defn accept-fun [service-fun sock] | |
(threaded | |
#(service-fun (. sock (getInputStream)) (. sock (getOutputStream))) | |
) | |
) | |
; Run a service on a given port | |
; The given service-fun should accept 2 arguments: the input and output channel | |
; of the connection it should handle | |
(defn run-service [service-fun port] | |
; Create the listening socket | |
(let [server (new ServerSocket port)] | |
; And run the following in a thread... | |
(threaded | |
; If our socket is not closed | |
#(when-not (. server (isClosed)) | |
; Accept incoming connection(s) | |
(try | |
; And run our accept helper given the new connection socket | |
(accept-fun service-fun (. server (accept))) | |
; Unless accept fails: we don't really care for now | |
(catch SocketException e) | |
) | |
; And keep on going | |
(recur) | |
) | |
) | |
) | |
) | |
; Our service function, takes 2 arguments | |
(defn echo [sin sout] | |
; Create a BufferedReader from the input socket | |
(let [rin (new BufferedReader (new InputStreamReader sin))] | |
; Set up a loop, reading one line from the input socket | |
(loop [line (. rin (readLine))] | |
; Dump it to the console | |
(println line) | |
; And send it back on the socket (adding a newline) | |
(. sout (write (. (str line "\n") getBytes))) | |
; Now read out the next line and go back to the start of this loop | |
(recur (. rin (readLine))) | |
) | |
) | |
) | |
; Set up our server | |
(def server (run-service echo 8000)) |
So, uh, where’s the code?
Oh, nevermind. Not the first time NoScript has made me look like a retard.
No problem
Maybe I should start to use some WP syntax highlighting plugin anyway, but I though LISP-style code really needs syntax highlighting to be readable for non-LISP people.
Where is the performance benchmark ?
None, first need to figure out what the characteristics to be benchmarked should be.