Like A Girl

Pushing the conversation on gender equality.

Code Like A Girl

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.

Socket Programming

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

Socket Hierarchy

Adding images of communication that happened between clients:

TCP SERVER accepting the client-connections
Client with username “neha” established the connection and ready to enter in chat mode.
Client with username “karan” established the connection and ready to enter in chat mode.

Fork me on GitHub.