2008-09-14 3 views
7

Я читаю строки ввода на сокете TCP, похожее на это:Восстановление разбитого TCP сокет в Ruby, когда получает()

class Bla 
    def getcmd 
    @sock.gets unless @sock.closed? 
    end 

    def start  
    srv = TCPServer.new(5000) 
    @sock = srv.accept 
    while ! @sock.closed? 
     ans = getcmd 
    end 
    end 
end 

Если конечная точка завершает соединение, пока GetLine() является выполняется, а затем получает() зависает.

Как я могу обойти это? Нужно ли делать неблокирующие или временные операции ввода-вывода?

ответ

-2

Если вы считаете, что rdoc для рубиновых сокетов, они не реализуют gets. Это заставляет меня полагать, что получение обеспечивается более высоким уровнем абстракции (возможно, библиотеки IO?) И, вероятно, не знает о сокет-специфических вещах, таких как «соединение закрыто».

Попробуйте использовать recvfrom вместо gets

6

Вы можете использовать выбрать, чтобы увидеть ли вы можете безопасно получает из гнезда, см следующей реализации TCPServer с помощью этой техники.

require 'socket' 

host, port = 'localhost', 7000 

TCPServer.open(host, port) do |server| 
    while client = server.accept 
    readfds = true 
    got = nil 
    begin 
     readfds, writefds, exceptfds = select([client], nil, nil, 0.1) 
     p :r => readfds, :w => writefds, :e => exceptfds 

     if readfds 
     got = client.gets 
     p got 
     end 
    end while got 
    end 
end 

А вот клиент, который пытается сломать сервер:

require 'socket' 

host, port = 'localhost', 7000 

TCPSocket.open(host, port) do |socket| 
    socket.puts "Hey there" 
    socket.write 'he' 
    socket.flush 
    socket.close 
end 
+0

Малой опечатка там, я считаю, что вы хотели: http://gist.github.com/527750 – rogerdpack 2010-08-16 21:14:08

2

НЛ # закрыт? возвращает true, когда и читатель, и писатель закрыты. В вашем случае @ sock.gets возвращает nil, а затем вы снова вызываете getcmd, и это выполняется в бесконечном цикле. Вы можете либо выбрать select, либо закрыть сокет, когда он возвращает nil.

+0

Если сокет закрыт получает повиснет – QueueHammer 2009-12-29 15:54:07

+0

да, если вы добавите печать «здесь» заявления в вашем getcmd цикла вы увидите, что это цикл навсегда, читая « – rogerdpack 2010-08-16 21:14:39

0

Я рекомендую использовать readpartial читать из вашей розетки, а также ловить одноранговые сбросы:

while true 
    sockets_ready = select(@sockets, nil, nil, nil) 
    if sockets_ready != nil 
     sockets_ready[0].each do |socket| 
     begin 
      if (socket == @server_socket) 
      # puts "Connection accepted!" 
      @sockets << @server_socket.accept 
      else 
      # Received something on a client socket 
      if socket.eof? 
       # puts "Disconnect!" 
       socket.close 
       @sockets.delete(socket) 
      else 
       data = "" 
       recv_length = 256 
       while (tmp = socket.readpartial(recv_length)) 
       data += tmp 
       break if (!socket.ready?) 
       end 
       listen socket, data 
      end 
      end 
     rescue Exception => exception 
      case exception 
      when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT 
       # puts "Socket: #{exception.class}" 
       @sockets.delete(socket) 
      else 
       raise exception 
      end 
     end 
     end 
    end 
    end 

Этот код заимствует из некоторого nice IBM code М. Тим Джонс. Обратите внимание, что @server_socket инициализируется:

@server_socket = TCPServer.open(port) 

@sockets - это всего лишь массив сокетов.

0

Я просто pgrep «ruby», чтобы найти pid, и убить -9 pid и перезапустить.

Смежные вопросы