IntroductionIn today's post, I'll demonstrate (and explain) how to put together a very simple TCP server in Haskell. The most simple example that I can think of, that will still leave you with enough skeleton to get up and running yourself is an echo server.
The Functional SpecificationAn Echo server. The drab, beige, sensible-older-brother in the server world. We'll accept incoming connections on a port and recite (echo) any data sent to us by the client. Simple.
DesignUsing the network, concurrency and system modules in Haskell, you're actually allowed a pretty simple and fluid design. Of course, you can make this as "one-liner" as you'd like, but for demonstration purposes today I'll break the server over a few parts:
- Main program
- Socket handler
- Echo implementation
Code WalkthroughThe main program is very simple. Setup the server socket using listenOn and then hand control over to the client handler.
The client handler (or socket handler as I called it above) accepts incoming client connections from the server socket using accept. We can then set buffering options (to off) for the client connection with hSetBuffering. From there we make the echo service implementation fire up on a thread of its own with forkIO. forkIO deserves a blog post of its own (as does the Concurrency module as a whole), and it will get one... just not today. Anyway, finally the client handler recurses on itself to handle the next client.
It's a lot of text for some pretty simple code in the end.
Finally, we have the actual implementation. This is the code that makes our server an echo server. We'll take a line of text in from the client socket using hGetLine then we'll write it back to the client using hPutStrLn.
And that's it. The full code listing for this echo server is below.
Final thoughtsThere is a fairly basic pattern that you can establish out of the module here that you can adapt for more complex servers of your own. Some further study of the IO system would be needed to develop binary communication protocols of your own, but if you're ok with plain text protocols - this should do just fine!