Reputation: 1991
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
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