cool.io icon indicating copy to clipboard operation
cool.io copied to clipboard

Cool.io::TCPServer continues to receive data even if its close method is called

Open abicky opened this issue 6 years ago • 2 comments

I expect Cool.io::TCPServer to stop receiving data after Cool.io::TCPServer#close is called, but it continues to receive data. Is this behavior expected?

Here is a reproducible code:

require 'socket'
require 'cool.io'

HOST = '127.0.0.1'
PORT = 1234

class ServerConnection < Coolio::TCPSocket
  def on_read(data)
    puts "received: #{data}"
  end
end

event_loop = Coolio::Loop.new
server = Cool.io::TCPServer.new(HOST, PORT, ServerConnection)
server.attach(event_loop)

server_thr = Thread.new { event_loop.run }
sock = TCPSocket.new(HOST, PORT)

puts "cool.io version: #{Coolio::VERSION}"

puts 'send a message'
sock.send "message", 0
sleep 1

server.close
puts 'server stopped'
sleep 1

puts 'send a message'
sock.send "message", 0
sleep 1

puts 'done'

Output

% docker run --rm -v $PWD/coolio_example.rb:/coolio_example.rb ruby:2.4.2 bash -c 'gem install cool.io && ruby /coolio_example.rb'
Building native extensions.  This could take a while...
Successfully installed cool.io-1.5.1
1 gem installed
cool.io version: 1.5.1
send a message
received: message
server stopped
send a message
received: message
done

abicky avatar Oct 22 '17 13:10 abicky

You need to call Loop#stop before server.close.

repeatedly avatar Oct 24 '17 01:10 repeatedly

I think this is expected behavior. What Cool.io::TCPServer#close does is just closing a socket listening*, not closing the accepted socket. the method is similar to TcpServer#close.

So here is the correct code to shutdown coolio.

require 'socket'
require  'cool.io'

HOST = '127.0.0.1'
PORT = 1234

class ServerConnection < Coolio::TCPSocket
  def on_read(data)
    puts "received: #{data}"
  end
end

event_loop = Coolio::Loop.new
conns = []
server = Cool.io::TCPServer.new(HOST, PORT, ServerConnection) do |conn|
  conns << conn
end
server.attach(event_loop)

server_thr = Thread.new { event_loop.run }
sock = TCPSocket.new(HOST, PORT)

puts "cool.io version: #{Coolio::VERSION}"

puts 'send a message'
sock.send "message", 0
sleep 1

server.close
conns.each do |c|
  c.close
end
puts 'server stopped'
sleep 1

puts 'send a message'
sock.send "message", 0
sleep 1

puts 'done'
$ docker run --rm -v $PWD/coolio_example.rb:/coolio_example.rb ruby:2.6 bash -c 'gem install cool.io && ruby /coolio_example.rb'
Building native extensions. This could take a while...
Successfully installed cool.io-1.5.4
1 gem installed
cool.io version: 1.5.4
send a message
received: message
server stopped
send a message
done

We can find another problem here. Calling second sock.send "message", 0 succeeded even if the accepted socket was already closed on the server-side. it seems to be related to https://github.com/fluent/fluentd/issues/1985 (also I don't think this is coolio's issue, it's a TCP stack issue).

ganmacs avatar Oct 03 '19 06:10 ganmacs

It sounds wrong to me, but please consider making a PR, as I don't think anyone is invested in maintaining this code base.

ioquatix avatar Aug 02 '23 10:08 ioquatix