Do you want to create custom network clients & servers in Ruby? Or just understand how that works?
Then you will have to deal with sockets.
Join me on this tour of ruby network programming to learn the basics, and start talking to other servers and clients using Ruby!
So what are sockets?
Sockets are the end points of the communication channel, both clients and servers use sockets to communicate.
The way they work is very simple:
Once a connection is established you can put data into your socket and it will make its way to the other end, where the receiver will read from the socket to process incoming data.
Socket Types
There are a few types of sockets available to you, the most common — the TCP Socket — will allow you to make connections to TCP-based services like HTTP or FTP.
If you have to use an UDP based protocol then you can use the UDP Socket.
The other types of sockets are a bit more esoterical, Unix sockets allow IPC (Inter-process communication) in Unix systems without the overhead of a full TCP connection.
Using Sockets in Ruby
Now that we know what sockets can do for us it is time to start using them.
First, require the sockets library into your program:
require 'socket'
To create a TCP socket you can use the TCPSocket class, as parameters you will need the destination IP address and port.
This will attempt to establish a connection, if it can’t be established then you will get a Errno::ECONNREFUSED error.
socket = TCPSocket.new('google.com', 80)
You should now be able to send messages through your socket, you will have to follow the protocol you are communicating with for the other end to be able to understand you.
socket.write "GET / HTTP/1.1" socket.write "\r\n\r\n"
Many of the methods you will be using come from the parent classes of TCPSocket
.
To read the response from the server you can use the recv method.
You need to pass the number of bytes that you want to read from the socket as a parameter:
puts socket.recv(100)
There is a small problem, you might not get any data back and your app will appear to be doing nothing.
The reason is that if there isn’t enough data to read, your program will ‘block’.
This means it will wait until there is some data available or the server closes the connection.
You may want to increase or decrease the amount of data you are reading depending on what protocol you are working with.
If blocking is an issue for you, check out the readpartial and read_nonblock methods from the IO class.
How to Write a TCP Server
Let’s build a server! The process is similar to writing the client, but we will need to tell the socket to bind to an interface, then listen on it, and finally to accept incoming connections.
The TCPServer class already does the first two for us.
Here is an example:
require 'socket' socket = TCPServer.new('0.0.0.0', 8080) client = socket.accept puts "New client! #{client}" client.write("Hello from server") client.close
Our example server will be listening on port 8080 and greet a connecting client with a message.
Notice how we can only accept one client and the program will end.
Accepting Multiple Clients
To be able to accept and respond to multiple clients, we will need a loop and some threads.
Example:
require 'socket' PORT = 8081 socket = TCPServer.new('0.0.0.0', PORT) def handle_connection(client) puts "New client! #{client}" client.write("Hello from server") client.close end puts "Listening on #{PORT}. Press CTRL+C to cancel." loop do client = socket.accept Thread.new { handle_connection(client) } end
That should start a new server that keeps listening until you stop it.
If you want to learn how to take this to the next level & write a web server in Ruby read this blog post.
Conclusion
You learned what TCP sockets are, how they work & how you can use some Ruby classes like TCPServer
& TCPSocket
to create Ruby applications that can interact with other machines on the internet.
Playing with ruby network programming is fun!
Now go create something cool and share it with everyone in the comments section 🙂
Also don’t forget to join my newsletter if you want to keep improving your Ruby skills!