I have some code similar to the following:
#!/usr/bin/env ruby
require 'socket'
server = TCPServer.new('localhost', 2000)
loop do
Thread.start(server.accept) do |client|
puts 'Client connects'
loop do
s = client.gets
break if s.index('quit') == 0
client.puts "Hello #{s}"
end
puts 'Client disconnects'
client.close
end
end
When this runs a new connection will spawn a new thread. If the user sends
the string starting with 'quit' then the connection will close
But if the use just terminates their session then the thread is left idle
waiting for input from a connection that no one is on the other end of.
Eventually I will end up with 100s of threads with no one to talk to
Is there a way for these threads to detect that the connection has been
lost? As opposed to someone just taking a very long time to communicate
s = client.gets
break if s.index('quit') == 0
[...]
But if the use just terminates their session then the thread is left idle
waiting for input from a connection that no one is on the other end
of.
I don't think this is true. A client terminating a session means that
the client closes its side of the TCP stream. This is going to cause an
EOF on the server, and thus IO#gets should return `nil' if the
connection is closed. Thus, in your example code, the thread handling
the terminating client is going to crash with a NoMethodError exception
(`nil' does not support the #index method).
Quote from <Class: IO (Ruby 2.6.2)
Returns nil if called at end of file.
Alternatively, there's IO#readline: <Class: IO (Ruby 2.6.2)
Reads a line as with IO#gets, but raises an EOFError on end of file.
If an exception is more convenient for you than just checking for `nil'.
···
Am 26. März 2019 um 11:38 Uhr +0000 schrieb Peter Hickman:
--
Blog: https://mg.guelker.eu
pry [1] is your friend
Add
require 'pry'
at the top of your code - add a
binding.pry
line just after your s = client.gets
Fire it up - connect and disconnect a client and see what happens - see
what the thread thinks about your disconnecting client and what it provides
you for information. There is at least one specific error with your code
and technically a better option than the loop ( while (s = client.gets)
.... ) - but the best option is to work your way through it by examining
what the code does.
John
[1] - GitHub - pry/pry: A runtime developer console and IRB alternative with powerful introspection capabilities.
···
On Tue, Mar 26, 2019 at 4:39 AM Peter Hickman < peterhickman386@googlemail.com> wrote:
I have some code similar to the following:
#!/usr/bin/env ruby
require 'socket'
server = TCPServer.new('localhost', 2000)
loop do
Thread.start(server.accept) do |client|
puts 'Client connects'
loop do
s = client.gets
break if s.index('quit') == 0
client.puts "Hello #{s}"
end
puts 'Client disconnects'
client.close
end
end
When this runs a new connection will spawn a new thread. If the user sends
the string starting with 'quit' then the connection will close
But if the use just terminates their session then the thread is left idle
waiting for input from a connection that no one is on the other end of.
Eventually I will end up with 100s of threads with no one to talk to
Is there a way for these threads to detect that the connection has been
lost? As opposed to someone just taking a very long time to communicate
Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
I've tested this by counting the threads. This is what I've put before the
main loop
Thread.start do
loop do
puts "Thread count #{Thread.list.count}"
sleep 5
end
end
Damn. The demo code I gave does reduce the number of threads. The real
application (somewhat larger) does not
Ignore this thread
Marvin is correct, my error handling is eating up the
problem with the nil being returned
Well that was an easy fix. Thank you both for your help
You might want `Thread.abort_on_exception = true` to make these things more evident.
···
On Mar 26, 2019, at 07:05, Peter Hickman <peterhickman386@googlemail.com> wrote:
Ignore this thread
Marvin is correct, my error handling is eating up the problem with the nil being returned