LDonoughe
LDonoughe

Reputation: 1

Ruby: TCPServer is not seeing that client TCPSocket has closed

While running a TCPServer in ruby 2.7.0, I want to see when my client has closed the connection (or is unable to continue reading). However, when I check on the server, I never see that the connection has closed.

I've tried using a bunch of the different ruby socket primitives but nothing seems to work here. I've tried writing to the socket as well in hopes of forcing an error but that doesn't seem to help.

I'm including an example here:

# main.rb

require_relative 'server'

PORT = 9000

server_thread = Server.thread
socket = TCPSocket.open("localhost", PORT)
socket.puts '5'
server_thread.join(1)
socket.close
puts socket.closed?
server_thread.join(2)
# server.rb

require 'socket'

class Server

  def self.thread
    Thread.new do
      server = TCPServer.open(PORT)
      while true
        server.accept do |socket|
          while true
            socket.puts '1'
            # why doesn't this ever happen?
            puts 'closed' if socket.closed?
          end
        end
      end
    end
  end
end

When running ruby main.rb, this code outputs

true

Whereas I expect it to output:

true
closed

Upvotes: 0

Views: 428

Answers (2)

LDonoughe
LDonoughe

Reputation: 1

The only response provided did not work. Attempting to read from the closed socket did not error like I expected it to.

I have come to the conclusion that what I was asking is simply not possible. You must either:

  1. Send a keep-alive from the client and close when you do not receive it or
  2. Face the consequences of not knowing whether or not your writes have succeeded.

Personally, I was able to live with 2 since this was for a prototype.

Upvotes: 0

Panic
Panic

Reputation: 2405

  1. The block that you pass to server.accept is ignored because Socket#accept does not accept a block argument.

  2. When you call socket.close in main.rb, you close the client side of the connection. The server side of the connection will remain open.

    You could call IO#read to wait until the client closes the connection.

    Thread.new do
      server = TCPServer.open(PORT)
      loop do
        socket = server.accept
        socket.read
        puts 'client closed connection'
        socket.eof? #=> true
        socket.close
      end
    end
    

Upvotes: 1

Related Questions