Skip to content


First Clojure experiments

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))
view raw gistfile1.clj hosted with ❤ by GitHub

Posted in Development, Technology.

Tagged with , , .


5 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Michael Orlitzky says

    So, uh, where’s the code?

  2. Michael Orlitzky says

    Oh, nevermind. Not the first time NoScript has made me look like a retard.

    • Nicolas says

      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.

  3. Geert Audenaert says

    Where is the performance benchmark ?

    • Nicolas says

      None, first need to figure out what the characteristics to be benchmarked should be.



Some HTML is OK

or, reply to this post via trackback.