Socket Programming in Ruby
Sockets are the endpoints of the communication channel, both clients and servers have to use sockets to communicate.
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 packets.

Using Sockets in Ruby
TCP Server
We need to tell the socket to bind to an interface, then listen on it, and finally to accept incoming connections.
require 'socket'
puts "Starting the Server..................."
server = TCPServer.open(3000) # Server would listen on port 3000
loop{ # Servers run forever
client_connection = server.accept # Establish client connect connection
client_connection.puts(Time.now) # Send the time to the client
client_connection.puts("Closing the connection with #{client_connection}")
client_connection.close # Disconnect from the client
}
TCP Client
require 'socket'
socket = TCPSocket.open("localhost", 3000)
puts "Starting the Client..................."
while message = socket.gets # Read lines from the socket
puts message.chomp
end
puts "Closing the Client..................."
socket.close # Close the socket
Accepting Multiple Clients
Let’s modify our server in order to handle multiple client request.
require 'socket'
puts "Starting the Server..................."
server = TCPServer.open(3000) # Server would listen on port 3000
loop{ # Servers run forever
client_connection = server.accept # Establish client connect connection
Thread.start(client_connection) do |connection|
connection.puts(Time.now) # Send the time to the client
connection.puts("Closing the connection with #{client_connection}")
connection.close # Disconnect from the client
end
}
Let’s build a small application to establish end-to-end communication:
Server
require 'socket'
class Server
def initialize(socket_address, socket_port)
@server_socket = TCPServer.open(socket_port, socket_address)
@connections_details = Hash.new
@connected_clients = Hash.new
@connections_details[:server] = @server_socket
@connections_details[:clients] = @connected_clients
puts 'Started server.........'
run
end
def run
loop{
client_connection = @server_socket.accept
Thread.start(client_connection) do |conn| # open thread for each accepted connection
conn_name = conn.gets.chomp.to_sym
if(@connections_details[:clients][conn_name] != nil) # avoid connection if user exits
conn.puts "This username already exist"
conn.puts "quit"
conn.kill self
end
puts "Connection established #{conn_name} => #{conn}"
@connections_details[:clients][conn_name] = conn
conn.puts "Connection established successfully #{conn_name} => #{conn}, you may continue with chatting....."
establish_chatting(conn_name, conn) # allow chatting
end
}.join
end
def establish_chatting(username, connection)
loop do
message = connection.gets.chomp
puts @connections_details[:clients]
(@connections_details[:clients]).keys.each do |client|
@connections_details[:clients][client].puts "#{username} : #{message}"
end
end
end
end
Server.new( 8080, "localhost" )
Client side
require 'socket'
class Client
def initialize(socket)
@socket = socket
@request_object = send_request
@response_object = listen_response
@request_object.join # will send the request to server
@response_object.join # will receive response from server
end
def send_request
puts "Please enter your username to establish a connection..."
begin
Thread.new do
loop do
message = $stdin.gets.chomp
@socket.puts message
end
end
rescue IOError => e
puts e.message
# e.backtrace
@socket.close
end
end
def listen_response
begin
Thread.new do
loop do
response = @socket.gets.chomp
puts "#{response}"
if response.eql?'quit'
@socket.close
end
end
end
rescue IOError => e
puts e.message
# e.backtrace
@socket.close
end
end
end
socket = TCPSocket.open( "localhost", 8080 )
Client.new( socket )
Socket hierarchy

Adding images of communication that happened between clients:


