TCPServer bug?

Hello.
I have a problem with TCP server like this

require "socket"
server = TCPServer.open(2000)
loop do
  Thread.start(server.accept) do |client|
    while msg = client.gets
      sleep 10
      client.puts "bye"
    end
  end
end

While server sleep if client breaking connection (hard break), server
becomes invalid: he can accept connections, but can not puts to client
any data and no exceptions return.
Ruby 1.9.2
What is happened?

*sorry for my english

···

--
Posted via http://www.ruby-forum.com/.

You'll probably do not see the exception because you do not catch and handle it. Try Thread.abort_on_exception = true at the beginning of the script to at least see the error.

Kind regards

  robert

···

On 27.10.2010 17:05, Yan Bernatsky wrote:

I have a problem with TCP server like this

require "socket"
server = TCPServer.open(2000)
loop do
   Thread.start(server.accept) do |client|
     while msg = client.gets
       sleep 10
       client.puts "bye"
     end
   end
end

While server sleep if client breaking connection (hard break), server
becomes invalid: he can accept connections, but can not puts to client
any data and no exceptions return.
Ruby 1.9.2
What is happened?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thank you, Robert.

I have an exception "Connection reset by peer" now and server continue
to works for another clients. But client, who break the connection,
can't connect to server again.

···

--
Posted via http://www.ruby-forum.com/.

This server is included into Rails app and initialized after
Application.initialize!

module Game
  class Server
    def initialize!
      Thread.abort_on_exception = true
      server = TCPServer.open(2000)
      Thread.new do
        begin
          loop do
            socket = server.accept
            Game::Client.new(socket) if socket
          end
        rescue => e
          puts "WARNING: #{e}"
        end
      end
    rescue => e
      puts "FATAL: #{e}"
    end
  end

  class Client
    include Response
    Actions = {}
    def initialize(client)
      puts "$ new client"
      @client = client
      Thread.abort_on_exception = true
      @mem = MemCache.new('localhost:11211')
      @user_id = nil
      Thread.new do
        while msg = @client.gets
          response_for_message(msg)
          sleep 2
        end
      end
      processing_user_events
    end

    private

    def processing_user_events
     # ...
    end

    def response_for_message(msg)
      puts "$$ start response_for_message"
      msg = msg.to_s.strip
      #puts "rqs: #{msg[0..80]}"
      case msg
      when "close" then
        @client.close
        puts "$ client close by message"
      else
        id, key, query = msg.split("#")
        response = get_response(id, key, query)
        response = "error: bad request" unless response
        send(response)
      end
    rescue => e
      puts "ERROR: #{e}"
      @client.close
      puts "$ client close"
    ensure
      puts "$$ end response_for_message"
    end

    def send(response)
      puts "$$$ start send"
      Timeout.timeout 5 do
        @client.puts response.to_s + "\0"
        #puts "rsp: #{response[0..80]}"
      end
    rescue => e
      puts "ERROR: #{e}"
      @client.close
      puts "INFO: client close"
    ensure
      puts "$$$ end send"
    end

    def get_response(id, key, query = "")
      puts "$$$ start get_response"
      params = {}
      CGI.parse(query.to_s).each_pair do |k, v|
        unless k.blank? and v.blank?
          params[k.to_sym] = v.first.to_s.strip
        end
      end
      puts "$$$$ 1"
      user = User.find_by_key(key.to_s.strip)
      puts "$$$$ 2"
      @user_id = user.id if user
      puts "$$$$ 3"
      if user.confirm
        puts "$$$$ 4"
        begin
          puts "$$$$ 5"
          puts "$$$$ start controllers"
          query = Actions[id.to_i]
          raise "Action not found" unless query
          query[:params].merge!(params)
          # ... => response
        rescue => e
          puts "ERROR: #{e};"
        ensure
          puts "$$$$ end controllers"
        end
      end
    rescue => e
      puts "ERROR: #{e}"
    ensure
      puts "$$$ end get_response"
    end
  end
end

debug:
$ new client
$$ start response_for_message
$$$ start get_response
$$$$ 1
$$$$ 2
$$$$ 3
$$$$ 4
$$$$ 5
$$$$ start controllers
$$$$ end controllers
$$$ end get_response
$$$ start send
$$$ end send
$$ end response_for_message
[2010-11-02 16:09:38] ERROR Errno::ECONNRESET: Connection reset by peer
  /Users/releu/Sites/mobile_wars/config/initializers/game_server.rb:57:in
`gets'
$ new client
$$ start response_for_message
$$$ start get_response
$$$$ 1
After this Rails is not responding for any clients.
What I missed?

···

--
Posted via http://www.ruby-forum.com/.

That's most likely an issue in your client code.

Cheers

robert

···

On Thu, Oct 28, 2010 at 10:12 AM, Yan Bernatsky <releu@me.com> wrote:

I have an exception "Connection reset by peer" now and server continue
to works for another clients. But client, who break the connection,
can't connect to server again.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi Yan,

If the client can reconnect after a few minutes (5 or so, depending on
OS), then you might need to set the socket option SO_REUSEADDR using
setsockopt before connecting.

  client_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )

HTH,
Ammar

···

On Thu, Oct 28, 2010 at 11:24 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

On Thu, Oct 28, 2010 at 10:12 AM, Yan Bernatsky <releu@me.com> wrote:

I have an exception "Connection reset by peer" now and server continue
to works for another clients. But client, who break the connection,
can't connect to server again.

That's most likely an issue in your client code.