1

im new in Ruby and Im trying to set up a TCPServer and a Client, but Im having trouble getting the data from the client to the server because for some reason when the client connects, the connection is freezed inside the while loop. Here is the code:

server.rb

require "socket"
server = TCPServer.new 1234
test = ""

loop do
  session = server.accept
  puts "Entering enter code herewhile loop."
  while line = session.gets
    puts "Inside while loop"
    test << line
  end
    puts "Finished reading data"

    puts "Data recieved - #{test}" # Read data from client
    session.write "Time is #{Time.now}" # Send data to clent
    session.close
end

client.rb

require "socket"

socket = TCPSocket.open("localhost", 1234)
socket.puts "Sending data.." # Send data to server
while(line = socket.gets)
  puts line
end # Print sever response
socket.close

The server prints "Inside while loop" one time, and then for some reason it never prints "Finished reading data" until I manually end the client connection, after the client ends the connection the server prints everything OK. How can I make this code work? Thanks!

SantiArias
  • 27
  • 4
  • The return value of `gets` is always truthy so the while loop will run forever. – max May 28 '21 at 01:39

1 Answers1

2

IO#gets is a blocking call. It waits for either a new line from the underlying I/O stream, or the end of the stream. (in which case it returns nil)

In server.rb you have

while line = session.gets
  puts "Inside while loop"
  test << line
end

session.gets reads one line from your client, prints some debug info and appends the line to test. It then attempts to read another line from the client.

Your client.rb however never sends a seconds line, nor does it close the stream. It sends a single line:

socket.puts "Sending data.." # Send data to server

and then waits for a response:

while(line = socket.gets)
  puts line
end

which never comes because the server is sitting in the while loop, waiting for more data from the client.

You can solve this by calling close_write after all data has been sent:

socket.puts "Sending data.." # Send data to server
socket.close_write           # Close socket for further writing

Calling close_write instead of close allows you to still read from the socket. It will also cause the server's session.gets to return nil, so it can get out of its loop.

Stefan
  • 109,145
  • 14
  • 143
  • 218
  • Oh thank you so much for the help! I didnt know what was causing it. I still dont understand why it gets stucked in the while loop, I thought that after socket.gets reads the line that the client sent, then when it tried to do socket.gets again in the next iteration it would return nil and hence get out of the while loop, does socket.gets not return nil if the client did not send anything? – SantiArias May 28 '21 at 15:46
  • @SantiArias the server can’t tell if that line was the final one or if more lines are going to arrive. As long as the stream is open, the client _could_ send more lines. That’s why (if no line is readily available) `gets` waits for one. It only returns `nil` at the end of the stream, i.e. when the client closes its "write end". – Stefan May 28 '21 at 19:00
  • Ok thank you again, you were very helpful! – SantiArias May 28 '21 at 20:18