« back

Building an Echo Server in Clojure - Part 2

20 Nov 2012

This time, let's get into implementation.

If you are just joining this post and are looking for context, I would suggest reading this and then this and then you should be up to speed.

As stated in this post, we are going to add socket-server into our dependencies.

1  
2     (defproject echo_server "1.0.0-SNAPSHOT"
3       :description "echo server in clojure"
4       :dependencies [[org.clojure/clojure "1.3.0"]
5     				[server-socket "1.0.0"]]
6       :dev-dependencies [[speclj "2.1.1"]]
7       :test-path "spec/"
8       :main echo_server.core
9     )

Okay. Let's define a namespace.

1  
2     (ns echo_server.core
3     	(:use server.socket))
4     (import '[java.io BufferedReader InputStreamReader OutputStreamWriter])

Great. Now what we want to do is define a port that we will be running this on. I randomly picked 1234.

1  
2     (ns echo_server.core
3     	(:use server.socket))
4     (import '[java.io BufferedReader InputStreamReader OutputStreamWriter])
5 
6     (def port 1234)

Now let's create an echo server function. In that function, we are going to want to make use of of the BufferedReader, InputStreamReader, and OutputStreamWriter that we imported with java.io, so that we can hook into standard in and standard out. Input and output seem self explanatory. BufferedReader is usually used when there is a difference between the rate at which data is received and the rate at which it can be processed. This can help with efficiency and acts as a little temporary storage hub for data.

Then, we want to actually give the instructions to create the echo effect. We will use loop. Inside it we will just print the line that we read. We will call recur to rebind to in and out and then jump back to the loop. Without calling recur, you can execute your echo only once and then the connection will close.

1 (def port 1234)
2 
3 (defn echo-server [in out]
4 	(binding [*in* (BufferedReader. (InputStreamReader. in))
5 			  *out* (OutputStreamWriter. out)]
6 		(loop []
7 			(println (read-line))
8 			(recur))))

The last thing we need to do is create a main function to kick off the execution of our program. We will want to use create-server and pass the functions port and echo-server to it.

1  
2 (defn -main []
3 (create-server port echo-server))

All together it looks like this...

 1  
 2 (ns echo_server.core
 3 	(:use server.socket))
 4 (import '[java.io BufferedReader InputStreamReader OutputStreamWriter])
 5 
 6 (def port 1234)
 7 
 8 (defn echo-server [in out]
 9 	(binding [*in* (BufferedReader. (InputStreamReader. in))
10 			  *out* (OutputStreamWriter. out)]
11 		(loop []
12 			(println (read-line))
13 			(recur))))
14 
15 (defn -main []
16 (create-server port echo-server))

Then you can do "lein run" on your command line in the project directory.

Once you see that you have a server running, you can use telnet(that should come on your machine) to connect to it. In a new terminal window with your server still running, type "telnet localhost 1234(or the port name you chose)" and then you should be in. Go ahead and type anything and you should see it echoed back to you.

Echo!!!!!

Echo!!!!!

comments powered by Disqus