Web basics: a TCP Server in Ruby
3 min read
This series guide covers the very basics of Web and the building blocks of a Web server.
If you have ever wondered on how a Web server works and have a basic knowledge of Ruby, this guide is for you.
Essentially, the main elementary units of a web server are:
- Client-server architecture model
- TCP - Transmission Control Protocol
- HTTP - Hypertext Transfer Protocol
Client-server model is a networking structure that allows different devices connecting to each other over a computer network, being local or public (Internet).
Consider two different devices connected to a network:
- the client (web browser) requests a webpage to the server
- the server (another computer in the network) that serves the requested webpage to the client
In order to establish a client-server connection, it's essential to indicate some kind of "agreement" among devices. Such agreement holds information like devices location, message being sent and so on.
This is the communication protocol, composed by layers ranging from physical material up to application traits.
We won't dig further into all layers but focus only on layers that contain TCP and HTTP. The following image illustrates the communication layers and its protocols:
Transmission Control Protocol is one of the main transport protocols in the OSI model. It embraces reliability and is responsible to deliver a message from one point to another.
In each device, we have to open endpoints that will be used by the TCP to send and receive data. A single computer can open and close thousands of endpoints. Those endpoints are called Sockets.
In Ruby we can implement a TCP client-server by using the package socket which is included in the standard library.
Let's create a
TCP client using
test/unit, which means: the test will be the client.
require 'socket' require 'test/unit' class ServerTest< Test::Unit::TestCase def test_tcp_request_response server = TCPSocket.open('localhost', 4242) request = 'Hello, server!' server.puts(request) response = server.gets assert_equal "Hey, client!\n", response server.close end end
- the test takes into account that we have opened a socket server in the port
localhostrefers to the same local machine, but it could be any valid location address in the internet
- the test (client) sends a request message to the server
- the test (client) reads the response message from the server
- the test (client) closes the socket connection to the server
If we try to run the test (
ruby tcp_test.rb), we'll get the following error:
SocketError: getaddrinfo: Name or service not known
Which means there's no opened socket server in the port 4242 of localhost. Let's make the test pass.
require 'socket' socket = TCPServer.new(4242) client = socket.accept request = client.gets response = 'Hey, client!' client.puts(response) client.close socket.close
- server creates a new socket in the port 4242
- server accepts connections to the socket and waits for a new connection to come in
- when a new client connection arrives, server reads the request message from the client
- server sends a response message to the client
- server closes the connection with client
- server closes the socket and terminates itself
Because the server must run in a separate process, we have to first:
- start the server,
- open a new tab or window, and run
Expectation: the test should pass and the server should terminate.
1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed
This post was the first part of series and an introduction to the client-server model along with building a simple TCP server in Ruby with TDD.
In the upcoming posts we'll learn about HTTP.