myhouse
myhouse

Reputation: 1991

communication between two clients in Ruby

I am trying to create a Ruby program that would send messages between two clients with the server in the middle. For example client A connects to server and client B connects to the same server and port. Client A says "How are you?" and client B says "Doing good." Kinda like a chat server. I am thinking on having the server take the message from client A and send to client B. So far I have this working client and server program that connects using a certificate. The problem I have is that my server sends back to client A and I do not know how to send to the second connection (client B).

client

#!/usr/bin/ruby
require "socket"
require "openssl"
require "thread"

host = ARGV[0]
port = Integer(ARGV[1])

socket = TCPSocket.new(host, port)
certificate = OpenSSL::X509::Certificate.new(File.open("server.crt"))
ssl = OpenSSL::SSL::SSLSocket.new(socket)
ssl.sync_close = true
ssl.connect
if ssl.peer_cert.to_s != certificate.to_s
  stderrr.puts "Unexpected certificate"
  exit(1)
end

# Get input through the server
Thread.new {
  begin
    while server_res = ssl.gets.chomp
      puts server_res
    end
  rescue
    $stderr.puts "Error in server response loop: " + $!
  end
}
# send out the STDIN to the server
while (client_sent = STDIN.gets.chomp)
  ssl.puts client_sent 
end

server

#!/usr/bin/ruby

require "socket"
require "openssl"
require "thread"

port = Integer(ARGV[0])
server = TCPServer.new(port)

sslCont = OpenSSL::SSL::SSLContext.new
sslCont.cert = OpenSSL::X509::Certificate.new(File.open("server.crt"))
sslCont.key = OpenSSL::PKey::RSA.new(File.open("server.key"))

sslServ = OpenSSL::SSL::SSLServer.new(server, sslCont)

loop {
  connection = sslServ.accept
  Thread.new {
    begin
      while (client_sent = connection.gets) do
        client_sent = client_sent.chomp
        puts "Client Sent: " + client_sent
        server_res = "Server Response: " + client_sent
        puts server_res
        connection.puts server_res
      end
    rescue
      $stderr.puts $!
    end
  }
}

Upvotes: 0

Views: 245

Answers (1)

Amadan
Amadan

Reputation: 198294

  • Keep an array of accepted connections

    connections = []
    
  • Keep it up to date when someone connects or disconnects

    connections << connection
    ...
    connections.delete(connection)
    
  • When sending, you can send to all of them:

    connections.each do |conn|
      conn.puts server_res
    end
    
  • Or just all except the current one:

    connections.each do |conn|
      next if conn == connection
      conn.puts server_res
    end
    
  • EDIT: Moved from comments because it's important: put connections.delete into the finally clause of the begin...rescue...finally...end block. This way, it gets executed when connection breaks for any reason (whether naturally from breaking the while condition, or unnaturally by exception). What you can't do is put it outside the thread block, because then each connection would be taken out of connections as soon as it was put in.

Upvotes: 2

Related Questions