简体   繁体   中英

TCPSocket connection cloing issue in Ruby

I'm pretty new in Ruby and I'm trying to implement Threading, but now I've got a mistake: client doesn't understand that connection has been closed.

Earlier, I wrote a simple tcp client-server app in C++, and the application works correct: if the server closed the connection, the client says that connection was closed too. But in Ruby nothing (as a client) happens and than the application exits with errors:

main.rb:34:in `write': Broken pipe (Errno::EPIPE)
    from main.rb:34:in `puts'
    from main.rb:34:in `block (2 levels) in send'
    from main.rb:32:in `loop'
    from main.rb:32:in `block in send'

So, here is the part of the source file of the C++ app. As you can see, if iResult equals 0 it means that the server has closed the connection.

if (iResult > 0) {
    std::string recievedString(recvbuf, recvbuf + iResult);
    std::cout << recievedString;
}
else if (iResult == 0) {
    std::cout << "Connection closed." << std::endl;
    break;
}

And it works fine.

There is Ruby server-client tcp apps:

CLIENT APP Yeah, sorry for these stupid methods..

#!/usr/bin/env ruby -w
require "socket"
class Client
  def initialize( server )
    @server = server
    @request = nil
    @response = nil
    listen
    send
    @request.join
    @response.join
  end

  def listen
    @response = Thread.new do
      loop {
        msg = @server.gets.chomp
        if msg == ""
          Thread.kill(@request)
          Thread.kill(@response)
        else
          puts msg
        end

      }
    end
  end

  def send
    puts "Enter the username:"
    @request = Thread.new do
      loop {
        msg = $stdin.gets.chomp
        @server.puts( msg )
      }
    end
  end
end

server = TCPSocket.open( "127.0.0.1", 6666 )
Client.new( server )

SERVER APP

#!/usr/bin/env ruby -w
require "socket"
class Server
  def initialize( port, ip )
    @server = TCPServer.open( ip, port )
    @connections = Hash.new
    @clients = Hash.new
    @connections[:server] = @server
    @connections[:clients] = @clients
    run
  end

  def run  
    loop {
      Thread.start(@server.accept) do | client |
        nick_name = client.gets.chomp.to_sym 
        puts nick_name
        @connections[:clients][nick_name] = client
        puts @connections.inspect
        client.puts "0001"
        listen_user_messages(nick_name, client)
        client.close
        Thread.kill self
      end
    }

  end

  def listen_user_messages( username, client )
    loop {
      msg = client.gets.chomp
      if msg == "0002"
        command = "Yah, two"
      else
        command = "Go home"
      end
      client.puts command
      break
    }
  end
end

Server.new( 6666, "127.0.0.1")

When a TCPSocket object is closed, calls to .gets will return nil . That means that your @server.gets.chomp will raise an error ( NoMethodError ) and the thread will terminate. To handle this case, you want to check the return value of the socket's .gets call.

  def listen
    @response = Thread.new do
      loop {
        msg = @server.gets
        if msg.nil?
          Thread.kill(@request)
          Thread.kill(@response)
        else
          puts msg.chomp
        end
      }
    end
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM